use { error_reporter::Report, indexmap::IndexMap, serde::{ de::{DeserializeOwned, Error}, Deserialize, Deserializer, }, }; #[derive(Debug, Deserialize)] pub struct Described { pub description: String, #[serde(flatten)] pub value: T, } #[derive(Debug)] pub enum TopLevelTypeSpec { Variable { variants: Vec>, }, Single(VariantSpec), } #[derive(Debug)] pub enum TableSpec { Tagged { types: IndexMap>, }, Single(SingleTableSpec), } #[derive(Debug, Deserialize)] pub struct SingleTableSpec { pub fields: IndexMap>, } #[derive(Debug, Deserialize)] pub struct TableFieldSpec { pub required: bool, #[serde(flatten)] pub kind: RefOrSpec, } #[derive(Debug)] pub enum RefOrSpec { Ref { name: String }, Spec(T), } #[derive(Debug, Deserialize)] pub struct StringSpec { pub values: Option>>, } #[derive(Debug, Deserialize)] pub struct StringSpecValue { pub value: String, } #[derive(Debug, Deserialize)] pub struct NumberSpec { #[serde(default)] pub integer_only: bool, pub minimum: Option, #[serde(default)] pub exclusive_minimum: bool, } #[derive(Debug, Deserialize)] #[serde(rename_all = "kebab-case", tag = "kind")] pub enum VariantSpec { String(RefOrSpec), Number(RefOrSpec), Boolean, Array(RefOrSpec), Table(RefOrSpec), } #[derive(Debug, Deserialize)] pub struct ArraySpec { pub items: Box>, } #[derive(Debug, Deserialize)] #[serde(rename_all = "kebab-case", tag = "kind")] pub enum NestableTypesSpec { String(StringSpec), Number(NumberSpec), Boolean, Array(ArraySpec), Map(MapSpec), } #[derive(Debug, Deserialize)] pub struct MapSpec { pub values: Box>, } impl<'de> Deserialize<'de> for TopLevelTypeSpec { fn deserialize(deserializer: D) -> Result where D: Deserializer<'de>, { let v = serde_yaml::Value::deserialize(deserializer)?; #[derive(Debug, Deserialize)] struct Variable { variants: Vec>, } let variable = Variable::deserialize(&v); let single = VariantSpec::deserialize(&v); let res = match (variable, single) { (Ok(variable), _) => Self::Variable { variants: variable.variants, }, (_, Ok(single)) => Self::Single(single), (Err(e1), Err(e2)) => { return Err(Error::custom(format!( "spec must define either variants or a single variant. failures: {} ----- {}", Report::new(e1), Report::new(e2) ))) } }; Ok(res) } } impl<'de> Deserialize<'de> for TableSpec { fn deserialize(deserializer: D) -> Result where D: Deserializer<'de>, { let v = serde_yaml::Value::deserialize(deserializer)?; #[derive(Debug, Deserialize)] struct Tagged { types: IndexMap>, } let tagged = Tagged::deserialize(&v); let single = SingleTableSpec::deserialize(&v); let res = match (tagged, single) { (Ok(tagged), _) => Self::Tagged { types: tagged.types, }, (_, Ok(single)) => Self::Single(single), (Err(e1), Err(e2)) => { return Err(Error::custom(format!( "spec must define either types or fields. failures: {} ----- {}", Report::new(e1), Report::new(e2) ))) } }; Ok(res) } } impl<'de, U: DeserializeOwned> Deserialize<'de> for RefOrSpec { fn deserialize(deserializer: D) -> Result where D: Deserializer<'de>, { let v = serde_yaml::Value::deserialize(deserializer)?; #[derive(Debug, Deserialize)] struct Ref { #[serde(rename = "ref")] name: String, } let name = Ref::deserialize(&v); let single = U::deserialize(&v); let res = match (name, single) { (Ok(name), _) => Self::Ref { name: name.name }, (_, Ok(single)) => Self::Spec(single), (Err(e1), Err(e2)) => { return Err(Error::custom(format!( "spec must define either a ref or a spec. failures: {} ----- {}", Report::new(e1), Report::new(e2) ))) } }; Ok(res) } }