use serde::{Deserialize, Serialize}; use serde_json::Value; use std::collections::BTreeMap; use std::sync::Arc; // Schema mirrors the Go Punc Generator's schema struct for consistency. // It is an order-preserving representation of a JSON Schema. #[derive(Debug, Clone, Serialize, Deserialize, Default)] pub struct SchemaObject { // Core Schema Keywords #[serde(rename = "$id")] pub id: Option, #[serde(rename = "$ref")] pub ref_string: Option, #[serde(rename = "$anchor")] pub anchor: Option, #[serde(rename = "$dynamicAnchor")] pub dynamic_anchor: Option, #[serde(rename = "$dynamicRef")] pub dynamic_ref: Option, /* Note: The `Ref` field in the Go struct is a pointer populated by the linker. In Rust, we might handle this differently (e.g., separate lookup or Rc/Arc), so we omit the direct recursive `Ref` field for now and rely on `ref_string`. */ pub description: Option, pub title: Option, #[serde(default)] // Allow missing type #[serde(rename = "type")] pub type_: Option, // Handles string or array of strings // Object Keywords pub properties: Option>>, #[serde(rename = "patternProperties")] pub pattern_properties: Option>>, #[serde(rename = "additionalProperties")] pub additional_properties: Option>, pub required: Option>, // dependencies can be schema dependencies or property dependencies pub dependencies: Option>, // Definitions (for $ref resolution) #[serde(rename = "$defs")] pub defs: Option>>, #[serde(rename = "definitions")] pub definitions: Option>>, // Array Keywords #[serde(rename = "items")] pub items: Option>, #[serde(rename = "prefixItems")] pub prefix_items: Option>>, // String Validation #[serde(rename = "minLength")] pub min_length: Option, #[serde(rename = "maxLength")] pub max_length: Option, pub pattern: Option, // Array Validation #[serde(rename = "minItems")] pub min_items: Option, #[serde(rename = "maxItems")] pub max_items: Option, #[serde(rename = "uniqueItems")] pub unique_items: Option, #[serde(rename = "contains")] pub contains: Option>, #[serde(rename = "minContains")] pub min_contains: Option, #[serde(rename = "maxContains")] pub max_contains: Option, // Object Validation #[serde(rename = "minProperties")] pub min_properties: Option, #[serde(rename = "maxProperties")] pub max_properties: Option, #[serde(rename = "propertyNames")] pub property_names: Option>, #[serde(rename = "dependentRequired")] pub dependent_required: Option>>, #[serde(rename = "dependentSchemas")] pub dependent_schemas: Option>>, // Numeric Validation pub format: Option, #[serde(rename = "enum")] pub enum_: Option>, // `enum` is a reserved keyword in Rust #[serde( default, rename = "const", deserialize_with = "crate::util::deserialize_some" )] pub const_: Option, // Numeric Validation #[serde(rename = "multipleOf")] pub multiple_of: Option, pub minimum: Option, pub maximum: Option, #[serde(rename = "exclusiveMinimum")] pub exclusive_minimum: Option, #[serde(rename = "exclusiveMaximum")] pub exclusive_maximum: Option, // Combining Keywords #[serde(rename = "allOf")] pub all_of: Option>>, #[serde(rename = "anyOf")] pub any_of: Option>>, #[serde(rename = "oneOf")] pub one_of: Option>>, #[serde(rename = "not")] pub not: Option>, #[serde(rename = "if")] pub if_: Option>, #[serde(rename = "then")] pub then_: Option>, #[serde(rename = "else")] pub else_: Option>, // Custom Vocabularies pub form: Option>, pub display: Option>, #[serde(rename = "enumNames")] pub enum_names: Option>, pub control: Option, pub actions: Option>, pub computer: Option, #[serde(default)] pub extensible: Option, // Compiled Fields (Hidden from JSON/Serde) #[serde(skip)] pub compiled_format: Option, #[serde(skip)] pub compiled_pattern: Option, #[serde(skip)] pub compiled_pattern_properties: Option)>>, #[serde(skip)] pub compiled_registry: Option>, } #[derive(Debug, Clone, Serialize)] pub struct Schema { #[serde(flatten)] pub obj: SchemaObject, #[serde(skip)] pub always_fail: bool, } impl Default for Schema { fn default() -> Self { Schema { obj: SchemaObject::default(), always_fail: false, } } } impl std::ops::Deref for Schema { type Target = SchemaObject; fn deref(&self) -> &Self::Target { &self.obj } } impl std::ops::DerefMut for Schema { fn deref_mut(&mut self) -> &mut Self::Target { &mut self.obj } } impl<'de> Deserialize<'de> for Schema { fn deserialize(deserializer: D) -> Result where D: serde::Deserializer<'de>, { let v: Value = Deserialize::deserialize(deserializer)?; if let Some(b) = v.as_bool() { let mut obj = SchemaObject::default(); if b { obj.extensible = Some(true); } return Ok(Schema { obj, always_fail: !b, }); } let obj: SchemaObject = serde_json::from_value(v.clone()).map_err(serde::de::Error::custom)?; Ok(Schema { obj, always_fail: false, }) } } #[derive(Debug, Clone, Serialize, Deserialize)] #[serde(untagged)] pub enum SchemaTypeOrArray { Single(String), Multiple(Vec), } #[derive(Debug, Clone, Serialize, Deserialize)] pub struct Action { pub navigate: Option, pub punc: Option, } #[derive(Debug, Clone, Serialize, Deserialize)] #[serde(untagged)] pub enum Dependency { Props(Vec), Schema(Arc), }