diff --git a/examples/update_schema.rs b/examples/update_schema.rs index a7ebcdc3..a8579b0c 100644 --- a/examples/update_schema.rs +++ b/examples/update_schema.rs @@ -14,7 +14,7 @@ use xsd_parser::config::{ }; use xsd_parser::generate; use xsd_parser::generator::GeneratorFlags; -use xsd_parser::types::{BuildInInfo, CustomType, IdentType, Type}; +use xsd_parser::types::{BuildInInfo, CustomType, IdentType, SimpleType, Type}; fn main() -> Result<(), Error> { fmt() @@ -54,13 +54,15 @@ fn main() -> Result<(), Error> { config.interpreter.types = vec![ ( IdentTriple::from((IdentType::Type, "xs:allNNI")), - Type::from(BuildInInfo::Custom( + Type::SimpleType(SimpleType::from(BuildInInfo::Custom( CustomType::new("MaxOccurs").with_default(max_occurs_default), - )), + ))), ), ( IdentTriple::from((IdentType::Type, "xs:QName")), - Type::from(BuildInInfo::Custom(CustomType::new("QName"))), + Type::SimpleType(SimpleType::from(BuildInInfo::Custom(CustomType::new( + "QName", + )))), ), ]; diff --git a/src/generator/data.rs b/src/generator/data.rs index 388733ce..b255a039 100644 --- a/src/generator/data.rs +++ b/src/generator/data.rs @@ -8,9 +8,7 @@ use crate::{ code::{format_field_ident, format_variant_ident, IdentPath, ModulePath}, schema::{xs::Use, MaxOccurs, MinOccurs, NamespaceId}, types::{ - AnyAttributeInfo, AnyInfo, AttributeInfo, BuildInInfo, ComplexInfo, DynamicInfo, - ElementInfo, EnumerationInfo, GroupInfo, Ident, ReferenceInfo, Type, TypeVariant, Types, - UnionInfo, UnionTypeInfo, VariantInfo, + TypeVariant, AnyAttributeInfo, AnyInfo, AttributeInfo, BuildInInfo, ComplexInfo, ComplexTypeVariant, DynamicInfo, ElementInfo, EnumerationInfo, GroupInfo, Ident, ReferenceInfo, SimpleTypeVariant, Type, TypeDescriptor, Types, UnionInfo, UnionTypeInfo, VariantInfo }, }; @@ -49,24 +47,53 @@ pub enum TypeData<'types> { } impl<'types> TypeData<'types> { + pub(super) fn new_simple( + tyv: &'types SimpleTypeVariant, + ident: &Ident, + config: &Config<'types>, + state: &mut State<'types>, + ) -> Result { + let req = Request::new(ident, config, state); + + Ok(match &tyv { + SimpleTypeVariant::Union(x) => Self::Union(UnionType::new(x, req)?), + SimpleTypeVariant::BuildIn(x) => Self::BuildIn(BuildInType::new(x)), + SimpleTypeVariant::Reference(x) => Self::Reference(ReferenceType::new(x, req)?), + SimpleTypeVariant::Enumeration(x) => { + Self::Enumeration(EnumerationType::new(x, req)?) + } + }) + } + pub(super) fn new( ty: &'types Type, ident: &Ident, config: &Config<'types>, state: &mut State<'types>, ) -> Result { - let req = Request::new(ident, config, state); - Ok(match &ty.variant { - TypeVariant::BuildIn(x) => Self::BuildIn(BuildInType::new(x)), - TypeVariant::Union(x) => Self::Union(UnionType::new(x, req)?), - TypeVariant::Dynamic(x) => Self::Dynamic(DynamicType::new(x, req)?), - TypeVariant::Reference(x) => Self::Reference(ReferenceType::new(x, req)?), - TypeVariant::Enumeration(x) => Self::Enumeration(EnumerationType::new(x, req)?), - TypeVariant::All(x) => Self::Complex(ComplexType::new_all(x, req)?), - TypeVariant::Choice(x) => Self::Complex(ComplexType::new_choice(x, req)?), - TypeVariant::Sequence(x) => Self::Complex(ComplexType::new_sequence(x, req)?), - TypeVariant::ComplexType(x) => Self::Complex(ComplexType::new_complex(x, req)?), + Ok(match ty { + Type::SimpleType(td) => Self::new_simple(td, ident, config, state)?, + Type::ComplexType(td) => { + if let ComplexTypeVariant::SimpleType(x) = &td.variant { + return Self::new_simple(x, ident, config, state); + } + + let req = Request::new(ident, config, state); + + match &td.variant { + ComplexTypeVariant::Reference(x) => Self::Reference(ReferenceType::new(x, req)?), + ComplexTypeVariant::Dynamic(x) => Self::Dynamic(DynamicType::new(x, req)?), + ComplexTypeVariant::All(x) => Self::Complex(ComplexType::new_all(x, req)?), + ComplexTypeVariant::Choice(x) => Self::Complex(ComplexType::new_choice(x, req)?), + ComplexTypeVariant::Sequence(x) => { + Self::Complex(ComplexType::new_sequence(x, req)?) + } + ComplexTypeVariant::ComplexType(x) => { + Self::Complex(ComplexType::new_complex(x, req)?) + } + ComplexTypeVariant::SimpleType(_) => unreachable!() + }}, }) } } @@ -214,7 +241,8 @@ impl<'types> DynamicType<'types> { .collect::, _>>() }) .transpose()?; - let derived_types = info + + let derived_types = info .derived_types .iter() .map(|ident| make_derived_type_data(&mut req, ident)) @@ -658,39 +686,39 @@ impl<'types> ComplexType<'types> { } fn new_complex(info: &'types ComplexInfo, mut req: Request<'_, 'types>) -> Result { - let (type_mode, elements, any_element) = match info.content.as_ref().and_then(|ident| { + let (type_mode, elements, any_element) = info.content.as_ref().and_then(|ident| { req.types .get_resolved_type(ident) - .map(|ty| (&ty.variant, ident)) - }) { - None => (TypeMode::Sequence, &[][..], None), - Some((TypeVariant::All(si), _)) => (TypeMode::All, &si.elements[..], si.any.as_ref()), - Some((TypeVariant::Choice(si), _)) => { - (TypeMode::Choice, &si.elements[..], si.any.as_ref()) + .map(|ty| (ty, ident)) + }).map_or( Ok((TypeMode::Sequence, &[][..], None)),|a| match a { + (Type::ComplexType(TypeDescriptor { variant: ComplexTypeVariant::All(si), ..}), _) => Ok((TypeMode::All, &si.elements[..], si.any.as_ref())), + (Type::ComplexType(TypeDescriptor { variant:ComplexTypeVariant::Choice(si), ..}), _) => { + Ok((TypeMode::Choice, &si.elements[..], si.any.as_ref())) } - Some((TypeVariant::Sequence(si), _)) => { - (TypeMode::Sequence, &si.elements[..], si.any.as_ref()) + (Type::ComplexType(TypeDescriptor { variant:ComplexTypeVariant::Sequence(si), ..}), _) => { + Ok((TypeMode::Sequence, &si.elements[..], si.any.as_ref())) } - Some(( - TypeVariant::BuildIn(_) - | TypeVariant::Union(_) - | TypeVariant::Enumeration(_) - | TypeVariant::Reference(_), + (Type::SimpleType(TypeDescriptor { variant: + SimpleTypeVariant::BuildIn(_) + | SimpleTypeVariant::Union(_) + | SimpleTypeVariant::Enumeration(_) + | SimpleTypeVariant::Reference(_), + ..}), ident, - )) => { + ) => { let content_ref = req.get_or_create_type_ref(ident.clone())?; let target_type = content_ref.to_ident_path(); - (TypeMode::Simple { target_type }, &[][..], None) + Ok((TypeMode::Simple { target_type }, &[][..], None)) } - Some((x, _)) => { + (x, _) => { let ident = &req.current_type_ref().type_ident; tracing::warn!("Complex type has unexpected content: ident={ident}, info={info:#?}, content={x:#?}!"); - (TypeMode::Sequence, &[][..], None) + Ok((TypeMode::Sequence, &[][..], None)) } - }; + })?; Self::new( req, @@ -1008,7 +1036,7 @@ impl ComplexTypeBase { ret.tag_name = Some(make_tag_name(req.types, req.ident)); ret.trait_impls = req.make_trait_impls()?; - if let Some(TypeVariant::ComplexType(ci)) = req.types.get_variant(req.ident) { + if let Some(ComplexTypeVariant::ComplexType(ci)) = req.types.get_complex_type(req.ident).map(|a| &a.variant) { ret.is_complex = true; ret.is_dynamic = ci.is_dynamic; } @@ -1266,6 +1294,7 @@ impl<'a, 'types> Request<'a, 'types> { ident: &Ident, ) -> Result { let types = self.types; + let ty = types .get(ident) .ok_or_else(|| Error::UnknownType(ident.clone()))?; @@ -1279,41 +1308,51 @@ impl<'a, 'types> Request<'a, 'types> { }; } + let ty = match ty { + Type::SimpleType(type_descriptor) => type_descriptor, + Type::ComplexType(_) => { + return Err(Error::InvalidDefaultValue( + ident.clone(), + default.to_owned(), + )) + }, + }; + match &ty.variant { - TypeVariant::BuildIn(BuildInInfo::U8) => build_in!(u8), - TypeVariant::BuildIn(BuildInInfo::U16) => build_in!(u16), - TypeVariant::BuildIn(BuildInInfo::U32) => build_in!(u32), - TypeVariant::BuildIn(BuildInInfo::U64) => build_in!(u64), - TypeVariant::BuildIn(BuildInInfo::U128) => build_in!(u128), - TypeVariant::BuildIn(BuildInInfo::Usize) => build_in!(usize), - - TypeVariant::BuildIn(BuildInInfo::I8) => build_in!(i8), - TypeVariant::BuildIn(BuildInInfo::I16) => build_in!(i16), - TypeVariant::BuildIn(BuildInInfo::I32) => build_in!(i32), - TypeVariant::BuildIn(BuildInInfo::I64) => build_in!(i64), - TypeVariant::BuildIn(BuildInInfo::I128) => build_in!(i128), - TypeVariant::BuildIn(BuildInInfo::Isize) => build_in!(isize), - - TypeVariant::BuildIn(BuildInInfo::F32) => build_in!(f32), - TypeVariant::BuildIn(BuildInInfo::F64) => build_in!(f64), - - TypeVariant::BuildIn(BuildInInfo::Bool) => { + SimpleTypeVariant::BuildIn(BuildInInfo::U8) => build_in!(u8), + SimpleTypeVariant::BuildIn(BuildInInfo::U16) => build_in!(u16), + SimpleTypeVariant::BuildIn(BuildInInfo::U32) => build_in!(u32), + SimpleTypeVariant::BuildIn(BuildInInfo::U64) => build_in!(u64), + SimpleTypeVariant::BuildIn(BuildInInfo::U128) => build_in!(u128), + SimpleTypeVariant::BuildIn(BuildInInfo::Usize) => build_in!(usize), + + SimpleTypeVariant::BuildIn(BuildInInfo::I8) => build_in!(i8), + SimpleTypeVariant::BuildIn(BuildInInfo::I16) => build_in!(i16), + SimpleTypeVariant::BuildIn(BuildInInfo::I32) => build_in!(i32), + SimpleTypeVariant::BuildIn(BuildInInfo::I64) => build_in!(i64), + SimpleTypeVariant::BuildIn(BuildInInfo::I128) => build_in!(i128), + SimpleTypeVariant::BuildIn(BuildInInfo::Isize) => build_in!(isize), + + SimpleTypeVariant::BuildIn(BuildInInfo::F32) => build_in!(f32), + SimpleTypeVariant::BuildIn(BuildInInfo::F64) => build_in!(f64), + + SimpleTypeVariant::BuildIn(BuildInInfo::Bool) => { match default.to_ascii_lowercase().as_str() { "true" | "yes" | "1" => return Ok(quote!(true)), "false" | "no" | "0" => return Ok(quote!(false)), _ => (), } } - TypeVariant::BuildIn(BuildInInfo::String) => { + SimpleTypeVariant::BuildIn(BuildInInfo::String) => { return Ok(quote!(String::from(#default))); } - TypeVariant::BuildIn(BuildInInfo::Custom(x)) => { + SimpleTypeVariant::BuildIn(BuildInInfo::Custom(x)) => { if let Some(x) = x.default(default) { return Ok(x); } } - TypeVariant::Enumeration(ei) => { + SimpleTypeVariant::Enumeration(ei) => { let module_path = ModulePath::from_namespace(current_ns, types); let target_type = type_ref.to_ident_path().relative_to(&module_path); @@ -1336,7 +1375,7 @@ impl<'a, 'types> Request<'a, 'types> { } } - TypeVariant::Union(ui) => { + SimpleTypeVariant::Union(ui) => { let module_path = ModulePath::from_namespace(current_ns, types); let target_type = type_ref.to_ident_path().relative_to(&module_path); @@ -1352,7 +1391,7 @@ impl<'a, 'types> Request<'a, 'types> { } } - TypeVariant::Reference(ti) => match Occurs::from_occurs(ti.min_occurs, ti.max_occurs) { + SimpleTypeVariant::Reference(ti) => match Occurs::from_occurs(ti.min_occurs, ti.max_occurs) { Occurs::Single => return self.get_default(current_ns, default, &ti.type_), Occurs::DynamicList if default.is_empty() => { let module_path = ModulePath::from_namespace(current_ns, types); @@ -1362,8 +1401,6 @@ impl<'a, 'types> Request<'a, 'types> { } _ => (), }, - - _ => (), } Err(Error::InvalidDefaultValue( @@ -1384,14 +1421,14 @@ impl<'types> Deref for Request<'_, 'types> { /* Helper */ fn is_dynamic(ident: &Ident, types: &Types) -> bool { - let Some(ty) = types.get(ident) else { + let Some(ty) = types.get_complex_type(ident) else { return false; }; match &ty.variant { - TypeVariant::Dynamic(_) => true, - TypeVariant::ComplexType(ci) => ci.is_dynamic, - TypeVariant::Reference(x) if x.is_single() => is_dynamic(&x.type_, types), + ComplexTypeVariant::Dynamic(_) => true, + ComplexTypeVariant::ComplexType(ci) => ci.is_dynamic, + ComplexTypeVariant::Reference(x) if x.is_single() => is_dynamic(&x.type_, types), _ => false, } } @@ -1422,7 +1459,7 @@ fn make_derived_type_data<'types>( .types .get(ident) .ok_or_else(|| Error::UnknownType(ident.clone()))?; - let base_ident = if let TypeVariant::Dynamic(di) = &ty.variant { + let base_ident = if let TypeVariant::ComplexType(ComplexTypeVariant::Dynamic(di)) = &ty.variant() { di.type_.clone() } else { None diff --git a/src/generator/helper.rs b/src/generator/helper.rs index 31368dfd..25443d19 100644 --- a/src/generator/helper.rs +++ b/src/generator/helper.rs @@ -1,7 +1,9 @@ use std::collections::{BTreeMap, HashSet}; use crate::schema::xs::Use; -use crate::types::{ComplexInfo, Ident, TypeVariant, Types}; +use crate::types::{ + ComplexInfo, ComplexType, ComplexTypeVariant, Ident, SimpleType, SimpleTypeVariant, Type, Types, +}; use super::misc::{Occurs, TypeRef}; @@ -33,13 +35,25 @@ impl<'a> Walk<'a> { let mut ret = false; - match self.types.get_variant(current) { - Some(TypeVariant::Reference(x)) => { + match self.types.get(current) { + Some( + Type::ComplexType(ComplexType { + variant: ComplexTypeVariant::Reference(x), + .. + }) + | Type::SimpleType(SimpleType { + variant: SimpleTypeVariant::Reference(x), + .. + }), + ) => { let occurs = Occurs::from_occurs(x.min_occurs, x.max_occurs); ret = occurs.is_direct() && self.is_loop(origin, &x.type_); } - Some(TypeVariant::Union(x)) => { + Some(Type::SimpleType(SimpleType { + variant: SimpleTypeVariant::Union(x), + .. + })) => { for var in x.types.iter() { if self.is_loop(origin, &var.type_) { ret = true; @@ -47,7 +61,10 @@ impl<'a> Walk<'a> { } } } - Some(TypeVariant::Enumeration(x)) => { + Some(Type::SimpleType(SimpleType { + variant: SimpleTypeVariant::Enumeration(x), + .. + })) => { for var in x.variants.iter() { if let Some(type_) = &var.type_ { if var.use_ != Use::Prohibited && self.is_loop(origin, type_) { @@ -57,17 +74,27 @@ impl<'a> Walk<'a> { } } } - Some(TypeVariant::ComplexType(ComplexInfo { - content: Some(content), - min_occurs, - max_occurs, + Some(Type::ComplexType(ComplexType { + variant: + ComplexTypeVariant::ComplexType(ComplexInfo { + content: Some(content), + min_occurs, + max_occurs, + .. + }), .. })) => { let occurs = Occurs::from_occurs(*min_occurs, *max_occurs); ret = occurs.is_direct() && self.is_loop(origin, content); } - Some(TypeVariant::All(x) | TypeVariant::Choice(x) | TypeVariant::Sequence(x)) => { + Some(Type::ComplexType(ComplexType { + variant: + ComplexTypeVariant::All(x) + | ComplexTypeVariant::Choice(x) + | ComplexTypeVariant::Sequence(x), + .. + })) => { for f in x.elements.iter() { let already_boxed = self .cache diff --git a/src/generator/misc.rs b/src/generator/misc.rs index 0b7570b2..335ce80c 100644 --- a/src/generator/misc.rs +++ b/src/generator/misc.rs @@ -7,7 +7,9 @@ use quote::quote; use crate::code::IdentPath; use crate::schema::{MaxOccurs, MinOccurs}; -use crate::types::{DynamicInfo, Ident, Type, TypeVariant, Types}; +use crate::types::{ + ComplexTypeVariant, DynamicInfo, Ident, SimpleTypeVariant, Type, TypeDescriptor, Types, +}; bitflags! { /// Different flags that control what code the [`Generator`](super::Generator) @@ -340,8 +342,8 @@ impl TraitInfos { pub(super) fn new(types: &Types) -> Self { let mut ret = Self(BTreeMap::new()); - for (base_ident, ty) in types.iter() { - let TypeVariant::Dynamic(ai) = &ty.variant else { + for (base_ident, variant) in types.complex_types_iter() { + let ComplexTypeVariant::Dynamic(ai) = variant else { continue; }; @@ -352,25 +354,40 @@ impl TraitInfos { .traits_all .insert(base_ident.clone()); - match types.get_variant(type_ident) { - Some(TypeVariant::Dynamic(DynamicInfo { - type_: Some(type_ident), + let Some(derived_type) = types.get(type_ident) else { + continue; + }; + + match derived_type { + Type::SimpleType(TypeDescriptor { + variant: SimpleTypeVariant::Reference(ri), + .. + }) + | Type::ComplexType(TypeDescriptor { + variant: ComplexTypeVariant::Reference(ri), .. - })) => { + }) if ri.is_single() => { ret.0 - .entry(type_ident.clone()) + .entry(ri.type_.clone()) .or_default() .traits_all .insert(base_ident.clone()); } - Some(TypeVariant::Reference(ri)) if ri.is_single() => { + Type::ComplexType(TypeDescriptor { + variant: + ComplexTypeVariant::Dynamic(DynamicInfo { + type_: Some(type_ident), + .. + }), + .. + }) => { ret.0 - .entry(ri.type_.clone()) + .entry(type_ident.clone()) .or_default() .traits_all .insert(base_ident.clone()); } - _ => (), + _ => {} } } } diff --git a/src/generator/mod.rs b/src/generator/mod.rs index 0d14c3fb..c226863e 100644 --- a/src/generator/mod.rs +++ b/src/generator/mod.rs @@ -20,7 +20,7 @@ use tracing::instrument; use crate::code::{format_module_ident, format_type_ident, IdentPath, Module}; use crate::schema::NamespaceId; -use crate::types::{Ident, IdentType, Name, Type, TypeVariant, Types}; +use crate::types::{ComplexTypeVariant, Ident, IdentType, Name, SimpleTypeVariant, Type, Types}; pub use self::context::Context; pub use self::data::{ @@ -499,13 +499,15 @@ impl<'types> State<'types> { .get(&ident) .ok_or_else(|| Error::UnknownType(ident.clone()))?; let name = make_type_name(&config.postfixes, ty, &ident); - let (module_ident, type_ident) = if let TypeVariant::BuildIn(x) = &ty.variant { + let (module_ident, type_ident) = if let Some(SimpleTypeVariant::BuildIn(x)) = + ty.simple_type_ref().map(|a| &a.variant) + { (None, format_ident!("{x}")) } else { let use_modules = config.flags.intersects(GeneratorFlags::USE_MODULES); let module_ident = format_module(config.types, use_modules.then_some(ident.ns).flatten())?; - let type_ident = format_type_ident(&name, ty.display_name.as_deref()); + let type_ident = format_type_ident(&name, ty.display_name()); (module_ident, type_ident) }; @@ -540,14 +542,18 @@ fn get_boxed_elements<'a>( types: &'a Types, cache: &BTreeMap, ) -> HashSet { - if let TypeVariant::ComplexType(ci) = &ty.variant { + if let Some(ComplexTypeVariant::ComplexType(ci)) = ty.complex_type_ref().map(|a| &a.variant) { if let Some(type_) = ci.content.as_ref().and_then(|ident| types.get(ident)) { ty = type_; } } - match &ty.variant { - TypeVariant::All(si) | TypeVariant::Choice(si) | TypeVariant::Sequence(si) => si + match ty.complex_type_ref().map(|a| &a.variant) { + Some( + ComplexTypeVariant::All(si) + | ComplexTypeVariant::Choice(si) + | ComplexTypeVariant::Sequence(si), + ) => si .elements .iter() .filter_map(|f| { @@ -563,7 +569,7 @@ fn get_boxed_elements<'a>( } fn make_type_name(postfixes: &[String], ty: &Type, ident: &Ident) -> Name { - if let TypeVariant::Reference(ti) = &ty.variant { + if let Some(ti) = ty.reference_type() { if ident.name.is_generated() && ti.type_.name.is_named() { if ti.min_occurs > 1 { return Name::new_generated(format!("{}List", ti.type_.name.to_type_name())); diff --git a/src/generator/renderer/quick_xml/deserialize.rs b/src/generator/renderer/quick_xml/deserialize.rs index b1e31a3a..8f62792a 100644 --- a/src/generator/renderer/quick_xml/deserialize.rs +++ b/src/generator/renderer/quick_xml/deserialize.rs @@ -20,7 +20,7 @@ use crate::{ Context, }, schema::{xs::Use, MaxOccurs}, - types::{ComplexInfo, ElementMode, Ident, TypeVariant, Types}, + types::{ComplexInfo, ComplexTypeVariant, ElementMode, Ident, Types}, }; /// Implements a [`Renderer`] that renders the code for the `quick_xml` deserialization. @@ -2194,15 +2194,15 @@ impl ComplexTypeElement<'_> { return false; } - match types.get_variant(ident) { - Some(TypeVariant::All(si) | TypeVariant::Choice(si)) => { + match types.get_complex_type(ident).map(|x| &x.variant) { + Some(ComplexTypeVariant::All(si) | ComplexTypeVariant::Choice(si)) => { if si.any.is_some() { return true; } si.elements.iter().any(|f| walk(types, visit, &f.type_)) } - Some(TypeVariant::Sequence(si)) => { + Some(ComplexTypeVariant::Sequence(si)) => { if si.any.is_some() { return true; } @@ -2213,7 +2213,7 @@ impl ComplexTypeElement<'_> { false } - Some(TypeVariant::ComplexType(ComplexInfo { + Some(ComplexTypeVariant::ComplexType(ComplexInfo { content: Some(content), .. })) => walk(types, visit, content), diff --git a/src/interpreter/builders/attribute_type.rs b/src/interpreter/builders/attribute_type.rs new file mode 100644 index 00000000..dd0a6b11 --- /dev/null +++ b/src/interpreter/builders/attribute_type.rs @@ -0,0 +1,158 @@ +use std::ops::{Deref, DerefMut}; + +use tracing::instrument; + +use super::Update; +use crate::schema::xs::AttributeType; +use crate::types::{ + AttributeInfo, ComplexInfo, ComplexType, ComplexTypeVariant, Ident, IdentType, Name, + ReferenceInfo, Type, VecHelper, +}; + +use super::super::{Error, SchemaInterpreter}; +use super::SimpleTypeBuilder; + +#[derive(Debug)] +pub(crate) struct AttributeTypeBuilder<'a, 'schema, 'state> { + type_: Option, + + /// Type variant that is constructed by the builder + variant: Option, + + owner: &'a mut SchemaInterpreter<'schema, 'state>, +} + +/* TypeBuilder */ + +impl<'a, 'schema, 'state> AttributeTypeBuilder<'a, 'schema, 'state> { + pub(crate) fn new(owner: &'a mut SchemaInterpreter<'schema, 'state>) -> Self { + Self { + type_: None, + variant: None, + owner, + } + } + + pub(crate) fn finish(self) -> Result { + self.type_ + .or_else(|| self.variant.map(ComplexType::new).map(Type::ComplexType)) + .ok_or(Error::NoType) + } + + fn get_or_init_complex(&mut self) -> &mut ComplexInfo { + match &mut self.variant { + Some(ComplexTypeVariant::ComplexType(ci)) => ci, + a @ None => { + *a = Some(ComplexTypeVariant::ComplexType(Default::default())); + + match a { + Some(ComplexTypeVariant::ComplexType(si)) => si, + _ => crate::unreachable!(), + } + } + Some(e) => crate::unreachable!("Type is expected to be a {:?}", e), + } + } + + #[instrument(err, level = "trace", skip(self))] + pub(crate) fn apply_attribute(&mut self, ty: &AttributeType) -> Result<(), Error> { + if let Some(type_) = &ty.type_ { + let type_ = self.parse_qname(type_)?; + + self.variant = Some(ComplexTypeVariant::Reference(ReferenceInfo::new(type_))); + } else if let Some(x) = &ty.simple_type { + let mut builder = SimpleTypeBuilder::new(self.owner); + builder.apply_simple_type(x)?; + + self.type_ = Some(builder.finish()?); + } + + Ok(()) + } + + #[instrument(err, level = "trace", skip(self))] + fn apply_attribute_ref(&mut self, ty: &AttributeType) -> Result<(), Error> { + match ty { + AttributeType { + name: Some(name), + type_: Some(type_), + .. + } => { + let type_ = self.parse_qname(type_)?; + let name = Name::from(name.clone()); + let ident = Ident::new(name) + .with_ns(self.state.current_ns()) + .with_type(IdentType::Attribute); + + let ci = self.get_or_init_complex(); + ci.attributes + .find_or_insert(ident, |ident| AttributeInfo::new(ident, type_)) + .update(ty); + } + AttributeType { + ref_: Some(ref_), + name, + .. + } => { + let type_ = self.parse_qname(ref_)?.with_type(IdentType::Attribute); + let name = self.state.name_builder().or(name).or(&type_.name).finish(); + let ident = Ident::new(name) + .with_ns(type_.ns) + .with_type(IdentType::Attribute); + + let ci = self.get_or_init_complex(); + ci.attributes + .find_or_insert(ident, |ident| AttributeInfo::new(ident, type_)) + .update(ty); + } + AttributeType { + name: Some(name), + simple_type, + .. + } => { + let type_ = simple_type + .as_ref() + .map(|x| { + let type_name = self + .state + .name_builder() + .or(name) + .auto_extend(true, true, self.state) + .finish(); + let ns = self.state.current_ns(); + + self.create_simple_type(ns, Some(type_name), None, x) + }) + .transpose()?; + let name = Name::from(name.clone()); + let ident = Ident::new(name) + .with_ns(self.state.current_ns()) + .with_type(IdentType::Attribute); + + let ci = self.get_or_init_complex(); + ci.attributes + .find_or_insert(ident, |ident| { + AttributeInfo::new(ident, type_.unwrap_or(Ident::STRING)) + }) + .update(ty); + } + e => return Err(Error::InvalidAttributeReference(Box::new(e.clone()))), + } + + Ok(()) + } +} + +impl<'schema, 'state> Deref for AttributeTypeBuilder<'_, 'schema, 'state> { + type Target = SchemaInterpreter<'schema, 'state>; + + fn deref(&self) -> &Self::Target { + self.owner + } +} + +impl DerefMut for AttributeTypeBuilder<'_, '_, '_> { + fn deref_mut(&mut self) -> &mut Self::Target { + self.owner + } +} diff --git a/src/interpreter/variant_builder.rs b/src/interpreter/builders/complex_type.rs similarity index 54% rename from src/interpreter/variant_builder.rs rename to src/interpreter/builders/complex_type.rs index 01956d95..a908536e 100644 --- a/src/interpreter/variant_builder.rs +++ b/src/interpreter/builders/complex_type.rs @@ -1,34 +1,33 @@ -use std::borrow::Cow; use std::collections::btree_map::Entry; use std::ops::{Deref, DerefMut}; -use std::str::from_utf8; use tracing::instrument; +use super::{CreateOrUpdate, Patch, Update}; +use crate::interpreter::builders::SimpleTypeBuilder; use crate::schema::xs::{ Any, AnyAttribute, AttributeGroupType, AttributeType, ComplexBaseType, ComplexContent, - ElementSubstitutionGroupType, ElementType, ExtensionType, Facet, FacetType, GroupType, List, - Restriction, RestrictionType, SimpleBaseType, SimpleContent, Union, Use, + ElementType, ExtensionType, Facet, GroupType, RestrictionType, SimpleContent, }; -use crate::schema::{MaxOccurs, MinOccurs, Namespace}; +use crate::schema::{MaxOccurs, MinOccurs}; use crate::types::{ - AnyAttributeInfo, AnyInfo, AttributeInfo, Base, DynamicInfo, ElementInfo, ElementMode, Ident, - IdentType, Name, ReferenceInfo, Type, TypeVariant, UnionTypeInfo, VariantInfo, VecHelper, + AnyInfo, AttributeInfo, Base, ComplexInfo, ComplexType, ComplexTypeVariant, ElementInfo, + ElementMode, GroupInfo, Ident, IdentType, Name, SimpleType, SimpleTypeVariant, Type, + TypeVariant, VecHelper, }; -use super::{Error, SchemaInterpreter}; +use super::super::{Error, SchemaInterpreter}; #[derive(Debug)] -pub(super) struct VariantBuilder<'a, 'schema, 'state> { +pub(crate) struct ComplexTypeBuilder<'a, 'schema, 'state> { + type_: Option, + /// Type variant that is constructed by the builder - variant: Option, + variant: Option, /// `true` if `type_` is fixed and can not be changed anymore fixed: bool, - /// Mode of the constructed type - type_mode: TypeMode, - /// Mode of the content of the constructed type content_mode: ContentMode, @@ -39,13 +38,6 @@ pub(super) struct VariantBuilder<'a, 'schema, 'state> { owner: &'a mut SchemaInterpreter<'schema, 'state>, } -#[derive(Debug, Clone, Copy, Eq, PartialEq)] -enum TypeMode { - Unknown, - Simple, - Complex, -} - #[derive(Debug, Clone, Copy, Eq, PartialEq)] enum ContentMode { Unknown, @@ -66,245 +58,88 @@ enum ComplexContentType { Sequence, } -/* any type */ - -/// Initialize the type of a `$builder` to any type `$variant`. -macro_rules! init_any { - ($builder:expr, $variant:ident) => { - init_any!($builder, $variant, Default::default(), true) - }; - ($builder:expr, $variant:ident, $value:expr, $fixed:expr) => {{ - $builder.variant = Some(TypeVariant::$variant($value)); - $builder.fixed = $fixed; - - let TypeVariant::$variant(ret) = $builder.variant.as_mut().unwrap() else { - crate::unreachable!(); - }; - - ret - }}; -} - -/// Get the type `$variant` of a `$builder` or set the type variant if unset. -macro_rules! get_or_init_any { - ($builder:expr, $variant:ident) => { - get_or_init_any!($builder, $variant, Default::default()) - }; - ($builder:expr, $variant:ident, $default:expr) => { - match &mut $builder.variant { - None => init_any!($builder, $variant, $default, true), - Some(TypeVariant::$variant(ret)) => ret, - _ if !$builder.fixed => init_any!($builder, $variant, $default, true), - Some(e) => crate::unreachable!("Type is expected to be a {:?}", e), - } - }; -} - -/// Get the `SimpleInfo` from any possible type or initialize the required variant. -macro_rules! get_or_init_type { - ($builder:expr, $variant:ident) => { - get_or_init_type!($builder, $variant, Default::default()) - }; - ($builder:expr, $variant:ident, $default:expr) => { - match &mut $builder.variant { - None => init_any!($builder, $variant, $default, true), - Some(TypeVariant::All(si) | TypeVariant::Choice(si) | TypeVariant::Sequence(si)) => si, - _ if !$builder.fixed => init_any!($builder, $variant, $default, true), - Some(e) => crate::unreachable!("Type is expected to be a {:?}", e), - } - }; -} - /* TypeBuilder */ -impl<'a, 'schema, 'state> VariantBuilder<'a, 'schema, 'state> { - pub(super) fn new(owner: &'a mut SchemaInterpreter<'schema, 'state>) -> Self { +impl<'a, 'schema, 'state> ComplexTypeBuilder<'a, 'schema, 'state> { + pub(crate) fn new(owner: &'a mut SchemaInterpreter<'schema, 'state>) -> Self { Self { + type_: None, variant: None, fixed: false, - type_mode: TypeMode::Unknown, content_mode: ContentMode::Unknown, is_simple_content_unique: false, owner, } } - pub(super) fn finish(self) -> Result { - let variant = self.variant.ok_or(Error::NoType)?; - - Ok(Type::new(variant)) + pub(crate) fn finish(self) -> Result { + self.type_ + .or_else(|| self.variant.map(ComplexType::new).map(Type::ComplexType)) + .ok_or(Error::NoType) } - #[instrument(err, level = "trace", skip(self))] - pub(super) fn apply_element(&mut self, ty: &ElementType) -> Result<(), Error> { - use crate::schema::xs::ElementTypeContent as C; - - if let Some(type_) = &ty.type_ { - let type_ = self.parse_qname(type_)?; - - init_any!(self, Reference, ReferenceInfo::new(type_), true); - } else if !ty.content.is_empty() { - let ident = self - .state - .current_ident() - .unwrap() - .clone() - .with_type(IdentType::ElementType); - - let mut has_content = false; - let type_ = self.create_type(ident, |builder| { - for c in &ty.content { - match c { - C::Annotation(_) - | C::Key(_) - | C::Alternative(_) - | C::Unique(_) - | C::Keyref(_) => {} - C::SimpleType(x) => { - has_content = true; - builder.apply_simple_type(x)?; - } - C::ComplexType(x) => { - has_content = true; - builder.apply_complex_type(x)?; - } - } + fn get_or_init_complex(&mut self) -> &mut ComplexInfo { + match &mut self.variant { + Some(ComplexTypeVariant::ComplexType(ci)) => ci, + a if !self.fixed | a.is_none() => { + *a = Some(ComplexTypeVariant::ComplexType(Default::default())); + self.fixed = true; + + match a { + Some(ComplexTypeVariant::ComplexType(si)) => si, + _ => crate::unreachable!(), } - - Ok(()) - }); - - if has_content { - init_any!(self, Reference, ReferenceInfo::new(type_?), true); } - } else { - let xs = self - .schemas - .resolve_namespace(&Some(Namespace::XS)) - .ok_or_else(|| Error::UnknownNamespace(Namespace::XS.clone()))?; - let ident = Ident::ANY_TYPE.with_ns(Some(xs)); - - init_any!(self, Reference, ReferenceInfo::new(ident), true); - } - - if ty.abstract_ { - let type_ = match self.variant.take() { - None => None, - Some(TypeVariant::Reference(ti)) => Some(ti.type_), - e => crate::unreachable!("Unexpected type: {:?}", e), - }; - - let ai = init_any!(self, Dynamic); - ai.type_ = type_; - } - - if let Some(substitution_group) = &ty.substitution_group { - self.walk_substitution_groups(substitution_group, |builder, base_ident| { - let ident = builder.state.current_ident().unwrap().clone(); - let base_ty = builder.get_element_mut(base_ident)?; - - if let TypeVariant::Reference(ti) = &mut base_ty.variant { - base_ty.variant = TypeVariant::Dynamic(DynamicInfo { - type_: Some(ti.type_.clone()), - derived_types: vec![ti.type_.clone()], - }); - } - - let TypeVariant::Dynamic(ai) = &mut base_ty.variant else { - return Err(Error::ExpectedDynamicElement(base_ident.clone())); - }; - - ai.derived_types.push(ident); - - Ok(()) - })?; - } - - Ok(()) - } - - #[instrument(err, level = "trace", skip(self))] - pub(super) fn apply_attribute(&mut self, ty: &AttributeType) -> Result<(), Error> { - if let Some(type_) = &ty.type_ { - let type_ = self.parse_qname(type_)?; - init_any!(self, Reference, ReferenceInfo::new(type_), false); - } else if let Some(x) = &ty.simple_type { - self.apply_simple_type(x)?; + Some(e) => crate::unreachable!("Type is expected to be a {:?}", e), + None => unreachable!( + "The a.is_none() branch should have been handled by the previous branch" + ), } - - Ok(()) } - #[instrument(err, level = "trace", skip(self))] - pub(super) fn apply_simple_type(&mut self, ty: &SimpleBaseType) -> Result<(), Error> { - use crate::schema::xs::SimpleBaseTypeContent as C; - - self.type_mode = TypeMode::Simple; - self.content_mode = ContentMode::Simple; - - for c in &ty.content { - match c { - C::Annotation(_) => (), - C::Restriction(x) => self.apply_simple_type_restriction(x)?, - C::Union(x) => self.apply_union(x)?, - C::List(x) => self.apply_list(x)?, - } + fn get_complex(&mut self) -> &mut ComplexInfo { + match &mut self.variant { + Some(ComplexTypeVariant::ComplexType(ci)) => ci, + a => unreachable!("Expected the type to be a complex type, but it is {:?}", a), } - - Ok(()) } - #[instrument(err, level = "trace", skip(self))] - fn apply_simple_type_restriction(&mut self, ty: &Restriction) -> Result<(), Error> { - use crate::schema::xs::RestrictionContent as C; - - let base = ty - .base - .as_ref() - .map(|base| { - let base = self.parse_qname(base)?; - - self.copy_base_type(&base, UpdateMode::Restriction)?; - - Ok(base) - }) - .transpose()?; - - for c in &ty.content { - match c { - C::Annotation(_) => (), - C::SimpleType(x) => self.apply_simple_type(x)?, - C::Facet(x) => self.apply_facet(x)?, - } - } - - if let Some(base) = base { - match &mut self.variant { - Some(TypeVariant::Reference(_)) => (), - Some(TypeVariant::Union(e)) => e.base = Base::Extension(base), - Some(TypeVariant::Enumeration(e)) => e.base = Base::Extension(base), - Some(TypeVariant::ComplexType(e)) => e.base = Base::Extension(base), - e => unreachable!("Unexpected type: {e:#?}"), + fn get_or_init_sequence(&mut self) -> &mut GroupInfo { + match &mut self.variant { + Some( + ComplexTypeVariant::All(si) + | ComplexTypeVariant::Choice(si) + | ComplexTypeVariant::Sequence(si), + ) => si, + a if !self.fixed | a.is_none() => { + *a = Some(ComplexTypeVariant::Sequence(Default::default())); + self.fixed = true; + + match a { + Some(ComplexTypeVariant::Sequence(si)) => si, + _ => crate::unreachable!(), + } } + Some(e) => crate::unreachable!("Type is expected to be a {:?}", e), + None => unreachable!( + "The a.is_none() branch should have been handled by the previous branch" + ), } - - Ok(()) } #[instrument(err, level = "trace", skip(self))] - pub(super) fn apply_complex_type(&mut self, ty: &ComplexBaseType) -> Result<(), Error> { + pub(crate) fn apply_complex_type(&mut self, ty: &ComplexBaseType) -> Result<(), Error> { use crate::schema::xs::ComplexBaseTypeContent as C; - self.type_mode = TypeMode::Complex; self.content_mode = ContentMode::Complex; - get_or_init_any!(self, ComplexType); + self.get_or_init_complex(); for c in &ty.content { match c { C::Annotation(_) | C::OpenContent(_) | C::Assert(_) => (), C::ComplexContent(x) => { - let ci = get_or_init_any!(self, ComplexType); + let ci = self.get_or_init_complex(); ci.is_dynamic = ty.abstract_; self.apply_complex_content(x)?; } @@ -343,7 +178,7 @@ impl<'a, 'schema, 'state> VariantBuilder<'a, 'schema, 'state> { fn apply_complex_content(&mut self, ty: &ComplexContent) -> Result<(), Error> { use crate::schema::xs::ComplexContentContent as C; - get_or_init_any!(self, ComplexType); + self.get_or_init_complex(); for c in &ty.content { match c { @@ -364,10 +199,10 @@ impl<'a, 'schema, 'state> VariantBuilder<'a, 'schema, 'state> { self.apply_extension(ty)?; match &mut self.variant { - Some(TypeVariant::Reference(_)) => (), - Some(TypeVariant::Union(e)) => e.base = Base::Extension(base), - Some(TypeVariant::Enumeration(e)) => e.base = Base::Extension(base), - Some(TypeVariant::ComplexType(e)) => e.base = Base::Extension(base), + Some(ComplexTypeVariant::Reference(_)) => (), + // Some(ComplexTypeVariant::Union(e)) => e.base = Base::Extension(base), + // Some(ComplexTypeVariant::Enumeration(e)) => e.base = Base::Extension(base), + Some(ComplexTypeVariant::ComplexType(e)) => e.base = Base::Extension(base), e => crate::unreachable!("Unexpected type: {e:#?}!"), } @@ -382,10 +217,10 @@ impl<'a, 'schema, 'state> VariantBuilder<'a, 'schema, 'state> { self.apply_restriction(ty)?; match &mut self.variant { - Some(TypeVariant::Reference(_)) => (), - Some(TypeVariant::Union(e)) => e.base = Base::Restriction(base), - Some(TypeVariant::Enumeration(e)) => e.base = Base::Restriction(base), - Some(TypeVariant::ComplexType(e)) => e.base = Base::Restriction(base), + Some(ComplexTypeVariant::Reference(_)) => (), + // Some(ComplexTypeVariant::Union(e)) => e.base = Base::Restriction(base), + // Some(ComplexTypeVariant::Enumeration(e)) => e.base = Base::Restriction(base), + Some(ComplexTypeVariant::ComplexType(e)) => e.base = Base::Restriction(base), e => crate::unreachable!("Unexpected type: {e:#?}!"), } @@ -399,7 +234,7 @@ impl<'a, 'schema, 'state> VariantBuilder<'a, 'schema, 'state> { self.copy_base_type(&base, UpdateMode::Extension)?; self.apply_extension(ty)?; - let ci = get_or_init_any!(self, ComplexType); + let ci = self.get_or_init_complex(); ci.base = Base::Extension(base); Ok(()) @@ -412,7 +247,7 @@ impl<'a, 'schema, 'state> VariantBuilder<'a, 'schema, 'state> { self.copy_base_type(&base, UpdateMode::Restriction)?; self.apply_restriction(ty)?; - let ci = get_or_init_any!(self, ComplexType); + let ci = self.get_or_init_complex(); ci.base = Base::Restriction(base); Ok(()) @@ -453,7 +288,11 @@ impl<'a, 'schema, 'state> VariantBuilder<'a, 'schema, 'state> { C::Facet(x) => self.apply_facet(x)?, C::Group(x) => self.apply_group_ref(x)?, C::Sequence(x) => self.apply_sequence(x)?, - C::SimpleType(x) => self.apply_simple_type(x)?, + C::SimpleType(x) => { + let mut builder = SimpleTypeBuilder::new(self.owner); + builder.apply_simple_type(x)?; + self.type_ = Some(builder.finish()?); + } } } @@ -541,7 +380,7 @@ impl<'a, 'schema, 'state> VariantBuilder<'a, 'schema, 'state> { .with_ns(type_.ns) .with_type(IdentType::Element); - let ci = get_or_init_type!(self, Sequence); + let ci = self.get_or_init_sequence(); let element = ci.elements.find_or_insert(ident, |ident| { ElementInfo::new(ident, type_, ElementMode::Element) }); @@ -568,7 +407,7 @@ impl<'a, 'schema, 'state> VariantBuilder<'a, 'schema, 'state> { let ns = self.state.current_ns(); let type_ = self.create_element(ns, Some(type_name), ty)?; - let ci = get_or_init_type!(self, Sequence); + let ci = self.get_or_init_sequence(); let element = ci.elements.find_or_insert(field_ident, |ident| { ElementInfo::new(ident, type_, ElementMode::Element) }); @@ -649,7 +488,7 @@ impl<'a, 'schema, 'state> VariantBuilder<'a, 'schema, 'state> { .with_ns(self.state.current_ns()) .with_type(IdentType::Attribute); - let ci = get_or_init_any!(self, ComplexType); + let ci = self.get_or_init_complex(); ci.attributes .find_or_insert(ident, |ident| AttributeInfo::new(ident, type_)) .update(ty); @@ -665,7 +504,7 @@ impl<'a, 'schema, 'state> VariantBuilder<'a, 'schema, 'state> { .with_ns(type_.ns) .with_type(IdentType::Attribute); - let ci = get_or_init_any!(self, ComplexType); + let ci = self.get_or_init_complex(); ci.attributes .find_or_insert(ident, |ident| AttributeInfo::new(ident, type_)) .update(ty); @@ -686,7 +525,7 @@ impl<'a, 'schema, 'state> VariantBuilder<'a, 'schema, 'state> { .finish(); let ns = self.state.current_ns(); - self.create_simple_type(ns, Some(type_name), x) + self.create_simple_type(ns, Some(type_name), None, x) }) .transpose()?; let name = Name::from(name.clone()); @@ -694,7 +533,7 @@ impl<'a, 'schema, 'state> VariantBuilder<'a, 'schema, 'state> { .with_ns(self.state.current_ns()) .with_type(IdentType::Attribute); - let ci = get_or_init_any!(self, ComplexType); + let ci = self.get_or_init_complex(); ci.attributes .find_or_insert(ident, |ident| { AttributeInfo::new(ident, type_.unwrap_or(Ident::STRING)) @@ -709,7 +548,7 @@ impl<'a, 'schema, 'state> VariantBuilder<'a, 'schema, 'state> { #[instrument(err, level = "trace", skip(self))] fn apply_any(&mut self, ty: &Any) -> Result<(), Error> { - let si = get_or_init_type!(self, Sequence); + let si = self.get_or_init_sequence(); si.any.create_or_update(ty); Ok(()) @@ -717,7 +556,7 @@ impl<'a, 'schema, 'state> VariantBuilder<'a, 'schema, 'state> { #[instrument(err, level = "trace", skip(self))] fn apply_any_attribute(&mut self, ty: &AnyAttribute) -> Result<(), Error> { - let ci = get_or_init_any!(self, ComplexType); + let ci = self.get_or_init_complex(); ci.any_attribute.create_or_update(ty); Ok(()) @@ -725,142 +564,45 @@ impl<'a, 'schema, 'state> VariantBuilder<'a, 'schema, 'state> { #[instrument(err, level = "trace", skip(self))] fn apply_facet(&mut self, ty: &Facet) -> Result<(), Error> { - match ty { - Facet::Enumeration(x) => self.apply_enumeration(x)?, - x => tracing::warn!("Unknown facet: {x:#?}"), - } - - Ok(()) - } - - #[instrument(err, level = "trace", skip(self))] - fn apply_enumeration(&mut self, ty: &FacetType) -> Result<(), Error> { - let name = Name::from(ty.value.trim().to_owned()); - let ident = Ident::new(name) - .with_ns(self.state.current_ns()) - .with_type(IdentType::Enumeration); - - self.simple_content_builder(|builder| { - let ei = get_or_init_any!(builder, Enumeration); - let var = ei.variants.find_or_insert(ident, VariantInfo::new); - var.use_ = Use::Required; - - Ok(()) - }) - } - - #[instrument(err, level = "trace", skip(self))] - fn apply_union(&mut self, ty: &Union) -> Result<(), Error> { - self.simple_content_builder(|builder| { - let ui = get_or_init_any!(builder, Union); - - if let Some(types) = &ty.member_types { - for type_ in &types.0 { - let type_ = builder.owner.parse_qname(type_)?; - ui.types.push(UnionTypeInfo::new(type_)); - } - } - - let ns = builder.owner.state.current_ns(); - - for x in &ty.simple_type { - let name = builder - .owner - .state - .name_builder() - .or(&x.name) - .auto_extend(false, true, builder.owner.state) - .finish(); - let type_ = builder.owner.create_simple_type(ns, Some(name), x)?; - ui.types.push(UnionTypeInfo::new(type_)); - } - - Ok(()) - }) - } - - #[instrument(err, level = "trace", skip(self))] - fn apply_list(&mut self, ty: &List) -> Result<(), Error> { - let mut type_ = None; - - if let Some(s) = &ty.item_type { - type_ = Some(self.owner.parse_qname(s)?); - } - - if let Some(x) = &ty.simple_type { - let last_named_type = self.state.last_named_type(false).map(ToOwned::to_owned); - let name = self - .state - .name_builder() - .or(&x.name) - .or_else(|| from_utf8(ty.item_type.as_ref()?.local_name()).ok()) - .or_else(|| { - let s = last_named_type?; - let s = s.as_str(); - let s = s.strip_suffix("Type").unwrap_or(s); - let s = format!("{s}Item"); - - Some(Name::from(s)) - }) - .finish(); - let ns = self.owner.state.current_ns(); - type_ = Some(self.owner.create_simple_type(ns, Some(name), x)?); - } - - if let Some(type_) = type_ { - self.simple_content_builder(|builder| { - let ti = get_or_init_any!(builder, Reference, ReferenceInfo::new(type_.clone())); - ti.type_ = type_; - ti.min_occurs = 0; - ti.max_occurs = MaxOccurs::Unbounded; - - Ok(()) - })?; - } - - Ok(()) + self.simple_content_builder(|builder| builder.apply_facet(ty)) } fn copy_base_type(&mut self, base: &Ident, mode: UpdateMode) -> Result<(), Error> { let mut simple_base_ident = None; - let base = match (self.type_mode, self.content_mode) { - (TypeMode::Simple, ContentMode::Simple) => { - self.fixed = false; + let base = match self.content_mode { + ContentMode::Simple => match self.owner.get_simple_type_variant(base) { + Ok(ty) => { + self.fixed = false; - simple_base_ident = Some(base.clone()); - - self.owner.get_simple_type_variant(base)? - } - (TypeMode::Complex, ContentMode::Simple) => { - match self.owner.get_simple_type_variant(base) { - Ok(ty) => { - self.fixed = false; + simple_base_ident = Some(base.clone()); - simple_base_ident = Some(base.clone()); - - ty - } - Err(Error::UnknownType(_)) => { - self.fixed = true; + TypeVariant::SimpleType(ty) + } + Err(Error::UnknownType(_)) => { + self.fixed = true; - self.owner.get_complex_type_variant(base)? - } - Err(error) => Err(error)?, + TypeVariant::ComplexType(self.owner.get_complex_type_variant(base)?) } + Err(error) => Err(error)?, + }, + ContentMode::Complex => { + TypeVariant::ComplexType(self.owner.get_complex_type_variant(base)?) } - (TypeMode::Complex, ContentMode::Complex) => { - self.owner.get_complex_type_variant(base)? - } - (_, _) => crate::unreachable!("Unset or invalid combination!"), + _ => crate::unreachable!("Unset or invalid combination!"), }; tracing::debug!("{base:#?}"); - let mut base = base.clone(); + let mut base = base.cloned(); match (self.content_mode, &mut base) { - (ContentMode::Simple, TypeVariant::Enumeration(ei)) => ei.variants.clear(), - (ContentMode::Complex, TypeVariant::ComplexType(ci)) => { + (ContentMode::Simple, TypeVariant::SimpleType(SimpleTypeVariant::Enumeration(ei))) => { + ei.variants.clear(); + } + ( + ContentMode::Complex, + TypeVariant::ComplexType(ComplexTypeVariant::ComplexType(ci)), + ) => { if let Some(content_ident) = &ci.content { let mut content_type = self .owner @@ -870,8 +612,8 @@ impl<'a, 'schema, 'state> VariantBuilder<'a, 'schema, 'state> { .ok_or_else(|| Error::UnknownType(content_ident.clone()))? .clone(); - match (&mut content_type.variant, mode) { - (TypeVariant::All(si) | TypeVariant::Choice(si) | TypeVariant::Sequence(si), UpdateMode::Restriction) => { + match (&mut content_type.variant_mut(), mode) { + (TypeVariant::ComplexType(ComplexTypeVariant::All(si) | ComplexTypeVariant::Choice(si) | ComplexTypeVariant::Sequence(si)), UpdateMode::Restriction) => { si.elements.retain(|element| element.min_occurs > 0); if matches!( @@ -900,16 +642,15 @@ impl<'a, 'schema, 'state> VariantBuilder<'a, 'schema, 'state> { (_, _) => (), } - match (simple_base_ident, self.type_mode, self.content_mode) { - (Some(_), TypeMode::Simple, _) => self.variant = Some(base), - (Some(base_ident), TypeMode::Complex, ContentMode::Simple) => { - let ci = get_or_init_any!(self, ComplexType); + match (simple_base_ident, self.content_mode) { + (Some(base_ident), ContentMode::Simple) => { + let ci = self.get_or_init_complex(); ci.content.get_or_insert(base_ident); } - (None, TypeMode::Complex, ContentMode::Simple | ContentMode::Complex) => { - self.variant = Some(base); + (None, ContentMode::Simple | ContentMode::Complex) => { + self.variant = Some(base.into_complex_type_variant()); } - (_, _, _) => crate::unreachable!("Unset or invalid combination!"), + (_, _) => crate::unreachable!("Unset or invalid combination!"), } tracing::debug!("{:#?}", self.variant); @@ -917,55 +658,23 @@ impl<'a, 'schema, 'state> VariantBuilder<'a, 'schema, 'state> { Ok(()) } - fn walk_substitution_groups( - &mut self, - groups: &ElementSubstitutionGroupType, - mut f: F, - ) -> Result<(), Error> - where - F: FnMut(&mut Self, &Ident) -> Result<(), Error>, - { - fn inner<'x, 'y, 'z, F>( - builder: &mut VariantBuilder<'x, 'y, 'z>, - groups: &ElementSubstitutionGroupType, - f: &mut F, - ) -> Result<(), Error> - where - F: FnMut(&mut VariantBuilder<'x, 'y, 'z>, &Ident) -> Result<(), Error>, - { - for head in &groups.0 { - let ident = builder.parse_qname(head)?.with_type(IdentType::Element); - - f(builder, &ident)?; - - if let Some(groups) = builder - .find_element(ident) - .and_then(|x| x.substitution_group.as_ref()) - { - inner(builder, groups, f)?; - } - } - - Ok(()) - } - - inner(self, groups, &mut f) - } - fn simple_content_builder(&mut self, f: F) -> Result<(), Error> where - F: FnOnce(&mut VariantBuilder<'_, 'schema, 'state>) -> Result<(), Error>, + F: FnOnce(&mut SimpleTypeBuilder<'_, 'schema, 'state>) -> Result<(), Error>, { - match (self.type_mode, self.content_mode) { - (TypeMode::Simple, _) => f(self)?, - (TypeMode::Complex, ContentMode::Simple) => { - let ci = get_or_init_any!(self, ComplexType); - - let Some(mut content_ident) = ci.content.clone() else { - crate::unreachable!( - "Complex type does not have a simple content identifier: {:?}", - &self.variant - ); + match self.content_mode { + ContentMode::Simple => { + let mut content_ident = { + let ci = self.get_or_init_complex(); + + let Some(content_ident) = ci.content.clone() else { + crate::unreachable!( + "Complex type does not have a simple content identifier: {:?}", + &self.variant + ); + }; + + content_ident }; let content = self.owner.get_simple_type_variant(&content_ident)?.clone(); @@ -974,18 +683,17 @@ impl<'a, 'schema, 'state> VariantBuilder<'a, 'schema, 'state> { let content_name = self.owner.state.make_content_name(); content_ident = Ident::new(content_name).with_ns(self.owner.state.current_ns()); + let ci = self.get_complex(); ci.content = Some(content_ident.clone()); } - let mut builder = VariantBuilder::new(&mut *self.owner); + let mut builder = SimpleTypeBuilder::new(&mut *self.owner); builder.variant = Some(content); - builder.type_mode = TypeMode::Simple; - builder.content_mode = ContentMode::Simple; f(&mut builder)?; let content = builder.variant.unwrap(); - let content = Type::new(content); + let content = Type::SimpleType(SimpleType::new(content)); match self.owner.state.types.entry(content_ident) { Entry::Vacant(e) => { @@ -996,10 +704,10 @@ impl<'a, 'schema, 'state> VariantBuilder<'a, 'schema, 'state> { } } } - (TypeMode::Complex, ContentMode::Complex) => { + ContentMode::Complex => { crate::unreachable!("Complex type with complex content tried to access simple content builder: {:?}", &self.variant); } - (_, _) => crate::unreachable!("Unset or invalid combination!"), + _ => crate::unreachable!("Unset or invalid combination!"), } Ok(()) @@ -1016,7 +724,7 @@ impl<'a, 'schema, 'state> VariantBuilder<'a, 'schema, 'state> { f: F, ) -> Result<(), Error> where - F: FnOnce(&mut VariantBuilder<'_, 'schema, 'state>) -> Result<(), Error>, + F: FnOnce(&mut ComplexTypeBuilder<'_, 'schema, 'state>) -> Result<(), Error>, { enum UpdateContentMode { Unknown, @@ -1027,7 +735,7 @@ impl<'a, 'schema, 'state> VariantBuilder<'a, 'schema, 'state> { let mut variant = None; let mut update_content_mode = UpdateContentMode::Unknown; - if let Some(TypeVariant::ComplexType(ci)) = &self.variant { + if let Some(ComplexTypeVariant::ComplexType(ci)) = &self.variant { if let Some(content_ident) = &ci.content { let content_ty = self .owner @@ -1036,11 +744,20 @@ impl<'a, 'schema, 'state> VariantBuilder<'a, 'schema, 'state> { .get(content_ident) .ok_or_else(|| Error::UnknownType(content_ident.clone()))?; - match (complex_content_type, &content_ty.variant) { - (ComplexContentType::All, TypeVariant::All(_)) - | (ComplexContentType::Choice, TypeVariant::Choice(_)) - | (ComplexContentType::Sequence, TypeVariant::Sequence(_)) => { - variant = Some(content_ty.variant.clone()); + match (complex_content_type, &content_ty.variant()) { + ( + ComplexContentType::All, + TypeVariant::ComplexType(new_variant @ ComplexTypeVariant::All(_)), + ) + | ( + ComplexContentType::Choice, + TypeVariant::ComplexType(new_variant @ ComplexTypeVariant::Choice(_)), + ) + | ( + ComplexContentType::Sequence, + TypeVariant::ComplexType(new_variant @ ComplexTypeVariant::Sequence(_)), + ) => { + variant = Some((*new_variant).clone()); update_content_mode = UpdateContentMode::Update; } (_, _) => update_content_mode = UpdateContentMode::Append, @@ -1049,21 +766,23 @@ impl<'a, 'schema, 'state> VariantBuilder<'a, 'schema, 'state> { } let variant = variant.unwrap_or_else(|| match complex_content_type { - ComplexContentType::All => TypeVariant::All(Default::default()), - ComplexContentType::Choice => TypeVariant::Choice(Default::default()), - ComplexContentType::Sequence => TypeVariant::Sequence(Default::default()), + ComplexContentType::All => ComplexTypeVariant::All(Default::default()), + ComplexContentType::Choice => ComplexTypeVariant::Choice(Default::default()), + ComplexContentType::Sequence => ComplexTypeVariant::Sequence(Default::default()), }); - let mut builder = VariantBuilder::new(&mut *self.owner); - builder.type_mode = self.type_mode; + let mut builder = ComplexTypeBuilder::new(&mut *self.owner); builder.variant = Some(variant); f(&mut builder)?; let ty = builder.finish()?; - let (TypeVariant::All(si) | TypeVariant::Choice(si) | TypeVariant::Sequence(si)) = - &ty.variant + let TypeVariant::ComplexType( + ComplexTypeVariant::All(si) + | ComplexTypeVariant::Choice(si) + | ComplexTypeVariant::Sequence(si), + ) = &ty.variant() else { return Err(Error::ExpectedGroupType); }; @@ -1075,7 +794,7 @@ impl<'a, 'schema, 'state> VariantBuilder<'a, 'schema, 'state> { let ns = self.state.current_ns(); match &mut self.variant { - Some(TypeVariant::ComplexType(ci)) => match update_content_mode { + Some(ComplexTypeVariant::ComplexType(ci)) => match update_content_mode { UpdateContentMode::Unknown => { self.owner.state.add_type(type_ident.clone(), ty, false)?; @@ -1096,11 +815,13 @@ impl<'a, 'schema, 'state> VariantBuilder<'a, 'schema, 'state> { let content_ident = ci.content.as_ref().unwrap(); let content_type = self.owner.state.types.get_mut(content_ident).unwrap(); - let content_variant = &mut content_type.variant; + let content_variant = &mut content_type.variant_mut(); - let (TypeVariant::All(si) - | TypeVariant::Choice(si) - | TypeVariant::Sequence(si)) = content_variant + let TypeVariant::ComplexType( + ComplexTypeVariant::All(si) + | ComplexTypeVariant::Choice(si) + | ComplexTypeVariant::Sequence(si), + ) = content_variant else { unreachable!(); }; @@ -1116,7 +837,11 @@ impl<'a, 'schema, 'state> VariantBuilder<'a, 'schema, 'state> { element.max_occurs = element.max_occurs.max(max_occurs); } }, - Some(TypeVariant::All(si) | TypeVariant::Choice(si) | TypeVariant::Sequence(si)) => { + Some( + ComplexTypeVariant::All(si) + | ComplexTypeVariant::Choice(si) + | ComplexTypeVariant::Sequence(si), + ) => { self.owner.state.add_type(type_ident.clone(), ty, false)?; let ident = Ident::new(field_name) @@ -1132,7 +857,7 @@ impl<'a, 'schema, 'state> VariantBuilder<'a, 'schema, 'state> { None => { self.owner.state.add_type(type_ident.clone(), ty, false)?; - let ci = get_or_init_any!(self, ComplexType); + let ci = self.get_or_init_complex(); ci.content = Some(type_ident); ci.min_occurs = ci.min_occurs.min(min_occurs); @@ -1166,7 +891,7 @@ impl<'a, 'schema, 'state> VariantBuilder<'a, 'schema, 'state> { } } -impl<'schema, 'state> Deref for VariantBuilder<'_, 'schema, 'state> { +impl<'schema, 'state> Deref for ComplexTypeBuilder<'_, 'schema, 'state> { type Target = SchemaInterpreter<'schema, 'state>; fn deref(&self) -> &Self::Target { @@ -1174,111 +899,8 @@ impl<'schema, 'state> Deref for VariantBuilder<'_, 'schema, 'state> { } } -impl DerefMut for VariantBuilder<'_, '_, '_> { +impl DerefMut for ComplexTypeBuilder<'_, '_, '_> { fn deref_mut(&mut self) -> &mut Self::Target { self.owner } } - -/* Update */ - -trait Update { - fn update(&mut self, other: &T); -} - -impl Update> for T { - fn update(&mut self, other: &Option) { - if let Some(value) = other { - *self = value.clone(); - } - } -} - -impl Update> for Option { - fn update(&mut self, other: &Option) { - if let Some(value) = other { - *self = Some(value.clone()); - } - } -} - -impl Update for ElementInfo { - fn update(&mut self, other: &GroupType) { - self.min_occurs = other.min_occurs; - self.max_occurs = other.max_occurs; - } -} - -impl Update for AnyInfo { - fn update(&mut self, other: &Any) { - self.min_occurs = Some(other.min_occurs); - self.max_occurs = Some(other.max_occurs); - self.process_contents = Some(other.process_contents.clone()); - - self.namespace.update(&other.namespace); - self.not_q_name.update(&other.not_q_name); - self.not_namespace.update(&other.not_namespace); - } -} - -impl Update for AnyAttributeInfo { - fn update(&mut self, other: &AnyAttribute) { - self.process_contents = Some(other.process_contents.clone()); - - self.namespace.update(&other.namespace); - self.not_q_name.update(&other.not_q_name); - self.not_namespace.update(&other.not_namespace); - } -} - -impl Update for ElementInfo { - fn update(&mut self, other: &ElementType) { - self.min_occurs = other.min_occurs; - self.max_occurs = other.max_occurs; - } -} - -impl Update for AttributeInfo { - fn update(&mut self, other: &AttributeType) { - self.use_ = other.use_.clone(); - self.default.update(&other.default); - } -} - -/* CreateOrUpdate */ - -trait CreateOrUpdate { - fn create_or_update(&mut self, other: &T); -} - -impl CreateOrUpdate for Option -where - X: Update + Default, -{ - fn create_or_update(&mut self, other: &T) { - if let Some(x) = self { - x.update(other); - } else { - let mut x = X::default(); - x.update(other); - *self = Some(x); - } - } -} - -/* Patch */ - -trait Patch: Clone { - fn patch(&self, other: &T) -> Cow<'_, Self>; -} - -impl Patch for GroupType { - fn patch(&self, other: &GroupType) -> Cow<'_, Self> { - let mut ret = self.clone(); - - ret.min_occurs = other.min_occurs; - ret.max_occurs = other.max_occurs; - - Cow::Owned(ret) - } -} diff --git a/src/interpreter/builders/element.rs b/src/interpreter/builders/element.rs new file mode 100644 index 00000000..21e8fb2f --- /dev/null +++ b/src/interpreter/builders/element.rs @@ -0,0 +1,213 @@ +use std::ops::{Deref, DerefMut}; + +use tracing::instrument; + +use crate::schema::xs::{ElementSubstitutionGroupType, ElementType}; +use crate::schema::Namespace; +use crate::types::{ + ComplexType, ComplexTypeVariant, DynamicInfo, Ident, IdentType, ReferenceInfo, + SimpleTypeVariant, Type, TypeDescriptor, +}; + +use super::super::{Error, SchemaInterpreter}; + +#[derive(Debug)] +pub(crate) struct ElementBuilder<'a, 'schema, 'state> { + /// Type variant that is constructed by the builder + variant: Option, + + owner: &'a mut SchemaInterpreter<'schema, 'state>, +} + +/* TypeBuilder */ + +impl ElementBuilder<'_, '_, '_> { + fn init_any(&mut self, variant: ComplexTypeVariant) -> &mut ComplexTypeVariant { + self.variant = Some(variant); + self.variant.as_mut().unwrap() + } +} + +impl<'a, 'schema, 'state> ElementBuilder<'a, 'schema, 'state> { + pub(crate) fn new(owner: &'a mut SchemaInterpreter<'schema, 'state>) -> Self { + Self { + variant: None, + owner, + } + } + + pub(crate) fn finish(self) -> Result { + self.variant + .map(ComplexType::new) + .map(Type::ComplexType) + .ok_or(Error::NoType) + } + + #[instrument(err, level = "trace", skip(self))] + pub(crate) fn apply_element(&mut self, ty: &ElementType) -> Result<(), Error> { + use crate::schema::xs::ElementTypeContent as C; + + if let Some(type_) = &ty.type_ { + let type_ = self.parse_qname(type_)?; + + self.init_any(ComplexTypeVariant::Reference(ReferenceInfo::new(type_))); + } else if !ty.content.is_empty() { + let ident = self + .state + .current_ident() + .unwrap() + .clone() + .with_type(IdentType::ElementType); + + let mut type_ = None; + for c in &ty.content { + match c { + C::Annotation(_) + | C::Key(_) + | C::Alternative(_) + | C::Unique(_) + | C::Keyref(_) => {} + C::SimpleType(x) => { + type_ = Some(self.create_simple_type( + ident.ns, + Some(ident.name), + Some(ident.type_), + x, + )?); + break; + } + C::ComplexType(x) => { + type_ = Some(self.create_complex_type( + ident.ns, + Some(ident.name), + Some(ident.type_), + x, + )?); + break; + } + } + } + + if let Some(type_) = type_ { + self.init_any(ComplexTypeVariant::Reference(ReferenceInfo::new(type_))); + } + } else { + let xs = self + .schemas + .resolve_namespace(&Some(Namespace::XS)) + .ok_or_else(|| Error::UnknownNamespace(Namespace::XS.clone()))?; + let ident = Ident::ANY_TYPE.with_ns(Some(xs)); + + self.init_any(ComplexTypeVariant::Reference(ReferenceInfo::new(ident))); + } + + if ty.abstract_ { + let type_ = match self.variant.take() { + None => None, + Some(ComplexTypeVariant::Reference(ti)) => Some(ti.type_), + e => crate::unreachable!("Unexpected type: {:?}", e), + }; + + let ComplexTypeVariant::Dynamic(ai) = + self.init_any(ComplexTypeVariant::Dynamic(Default::default())) + else { + crate::unreachable!(); + }; + ai.type_ = type_; + } + + if let Some(substitution_group) = &ty.substitution_group { + self.walk_substitution_groups(substitution_group, |builder, base_ident| { + let ident = builder.state.current_ident().unwrap().clone(); + let base_ty = builder.get_element_mut(base_ident)?; + + if let Type::ComplexType(TypeDescriptor { + display_name, + variant: ComplexTypeVariant::Reference(ti), + .. + }) + | Type::SimpleType(TypeDescriptor { + display_name, + variant: SimpleTypeVariant::Reference(ti), + .. + }) = base_ty + { + let dyn_info = DynamicInfo { + type_: Some(ti.type_.clone()), + derived_types: vec![ti.type_.clone()], + }; + + let display_name = display_name.take(); + + *base_ty = Type::ComplexType(TypeDescriptor { + display_name, + variant: ComplexTypeVariant::Dynamic(dyn_info), + }); + } + + let Type::ComplexType(TypeDescriptor { + variant: ComplexTypeVariant::Dynamic(ai), + .. + }) = base_ty + else { + return Err(Error::ExpectedDynamicElement(base_ident.clone())); + }; + + ai.derived_types.push(ident); + + Ok(()) + })?; + } + + Ok(()) + } + + fn walk_substitution_groups( + &mut self, + groups: &ElementSubstitutionGroupType, + mut f: F, + ) -> Result<(), Error> + where + F: FnMut(&mut Self, &Ident) -> Result<(), Error>, + { + fn inner<'x, 'y, 'z, F>( + builder: &mut ElementBuilder<'x, 'y, 'z>, + groups: &ElementSubstitutionGroupType, + f: &mut F, + ) -> Result<(), Error> + where + F: FnMut(&mut ElementBuilder<'x, 'y, 'z>, &Ident) -> Result<(), Error>, + { + for head in &groups.0 { + let ident = builder.parse_qname(head)?.with_type(IdentType::Element); + + f(builder, &ident)?; + + if let Some(groups) = builder + .find_element(ident) + .and_then(|x| x.substitution_group.as_ref()) + { + inner(builder, groups, f)?; + } + } + + Ok(()) + } + + inner(self, groups, &mut f) + } +} + +impl<'schema, 'state> Deref for ElementBuilder<'_, 'schema, 'state> { + type Target = SchemaInterpreter<'schema, 'state>; + + fn deref(&self) -> &Self::Target { + self.owner + } +} + +impl DerefMut for ElementBuilder<'_, '_, '_> { + fn deref_mut(&mut self) -> &mut Self::Target { + self.owner + } +} diff --git a/src/interpreter/builders/mod.rs b/src/interpreter/builders/mod.rs new file mode 100644 index 00000000..4201c66f --- /dev/null +++ b/src/interpreter/builders/mod.rs @@ -0,0 +1,116 @@ +mod element; +pub(crate) use element::ElementBuilder; +mod simple_type; +pub(crate) use simple_type::SimpleTypeBuilder; +mod complex_type; +pub(crate) use complex_type::ComplexTypeBuilder; +mod attribute_type; +pub(crate) use attribute_type::AttributeTypeBuilder; + +use std::borrow::Cow; + +use crate::schema::xs::{Any, AnyAttribute, AttributeType, ElementType, GroupType}; +use crate::types::{AnyAttributeInfo, AnyInfo, AttributeInfo, ElementInfo}; + +/* Update */ + +pub(crate) trait Update { + fn update(&mut self, other: &T); +} + +impl Update> for T { + fn update(&mut self, other: &Option) { + if let Some(value) = other { + *self = value.clone(); + } + } +} + +impl Update> for Option { + fn update(&mut self, other: &Option) { + if let Some(value) = other { + *self = Some(value.clone()); + } + } +} + +impl Update for ElementInfo { + fn update(&mut self, other: &GroupType) { + self.min_occurs = other.min_occurs; + self.max_occurs = other.max_occurs; + } +} + +impl Update for AnyInfo { + fn update(&mut self, other: &Any) { + self.min_occurs = Some(other.min_occurs); + self.max_occurs = Some(other.max_occurs); + self.process_contents = Some(other.process_contents.clone()); + + self.namespace.update(&other.namespace); + self.not_q_name.update(&other.not_q_name); + self.not_namespace.update(&other.not_namespace); + } +} + +impl Update for AnyAttributeInfo { + fn update(&mut self, other: &AnyAttribute) { + self.process_contents = Some(other.process_contents.clone()); + + self.namespace.update(&other.namespace); + self.not_q_name.update(&other.not_q_name); + self.not_namespace.update(&other.not_namespace); + } +} + +impl Update for ElementInfo { + fn update(&mut self, other: &ElementType) { + self.min_occurs = other.min_occurs; + self.max_occurs = other.max_occurs; + } +} + +impl Update for AttributeInfo { + fn update(&mut self, other: &AttributeType) { + self.use_ = other.use_.clone(); + self.default.update(&other.default); + } +} + +/* CreateOrUpdate */ + +pub(crate) trait CreateOrUpdate { + fn create_or_update(&mut self, other: &T); +} + +impl CreateOrUpdate for Option +where + X: Update + Default, +{ + fn create_or_update(&mut self, other: &T) { + if let Some(x) = self { + x.update(other); + } else { + let mut x = X::default(); + x.update(other); + *self = Some(x); + } + } +} + +/* Patch */ + +pub(crate) trait Patch: Clone { + fn patch(&self, other: &T) -> Cow<'_, Self>; +} + +impl Patch for GroupType { + fn patch(&self, other: &GroupType) -> Cow<'_, Self> { + let mut ret = self.clone(); + + ret.min_occurs = other.min_occurs; + ret.max_occurs = other.max_occurs; + + Cow::Owned(ret) + } +} diff --git a/src/interpreter/builders/simple_type.rs b/src/interpreter/builders/simple_type.rs new file mode 100644 index 00000000..51795e59 --- /dev/null +++ b/src/interpreter/builders/simple_type.rs @@ -0,0 +1,286 @@ +use std::ops::{Deref, DerefMut}; +use std::str::from_utf8; + +use tracing::instrument; + +use crate::schema::xs::{Facet, FacetType, List, Restriction, SimpleBaseType, Union, Use}; +use crate::schema::MaxOccurs; +use crate::types::{ + Base, EnumerationInfo, Ident, IdentType, Name, ReferenceInfo, SimpleType, SimpleTypeVariant, + Type, UnionInfo, UnionTypeInfo, VariantInfo, VecHelper, +}; + +use super::super::{Error, SchemaInterpreter}; + +#[derive(Debug)] +pub(crate) struct SimpleTypeBuilder<'a, 'schema, 'state> { + /// Type variant that is constructed by the builder + pub variant: Option, + + /// `true` if `type_` is fixed and can not be changed anymore + pub fixed: bool, + + pub owner: &'a mut SchemaInterpreter<'schema, 'state>, +} + +/* any type */ + +#[derive(Debug, Clone, Copy, Eq, PartialEq)] +#[allow(dead_code)] +enum UpdateMode { + Extension, + Restriction, +} + +/* TypeBuilder */ + +impl<'a, 'schema, 'state> SimpleTypeBuilder<'a, 'schema, 'state> { + pub(crate) fn new(owner: &'a mut SchemaInterpreter<'schema, 'state>) -> Self { + Self { + variant: None, + fixed: false, + owner, + } + } + + pub(crate) fn finish(self) -> Result { + self.variant + .map(SimpleType::new) + .map(Type::SimpleType) + .ok_or(Error::NoType) + } + + fn get_or_init_enumeration( + variant: &mut Option, + fixed: bool, + ) -> &mut EnumerationInfo { + match variant { + Some(SimpleTypeVariant::Enumeration(ei)) => ei, + a if !fixed || a.is_none() => { + *a = Some(SimpleTypeVariant::Enumeration(Default::default())); + match a { + Some(SimpleTypeVariant::Enumeration(ei)) => ei, + _ => crate::unreachable!(), + } + } + Some(e) => crate::unreachable!("Type is expected to be a {:?}", e), + None => crate::unreachable!("Cant be reached"), + } + } + + fn get_or_init_union(variant: &mut Option, fixed: bool) -> &mut UnionInfo { + match variant { + Some(SimpleTypeVariant::Union(ei)) => ei, + a if !fixed || a.is_none() => { + *a = Some(SimpleTypeVariant::Union(Default::default())); + match a { + Some(SimpleTypeVariant::Union(ei)) => ei, + _ => crate::unreachable!(), + } + } + Some(e) => crate::unreachable!("Type is expected to be a {:?}", e), + None => crate::unreachable!("Cant be reached"), + } + } + + fn get_or_init_reference( + variant: &mut Option, + fixed: bool, + ei: ReferenceInfo, + ) -> &mut ReferenceInfo { + match variant { + Some(SimpleTypeVariant::Reference(ei)) => ei, + a if !fixed || a.is_none() => { + *a = Some(SimpleTypeVariant::Reference(ei)); + match a { + Some(SimpleTypeVariant::Reference(ei)) => ei, + _ => crate::unreachable!(), + } + } + Some(e) => crate::unreachable!("Type is expected to be a {:?}", e), + None => crate::unreachable!("Cant be reached"), + } + } + + #[instrument(err, level = "trace", skip(self))] + pub(crate) fn apply_simple_type(&mut self, ty: &SimpleBaseType) -> Result<(), Error> { + use crate::schema::xs::SimpleBaseTypeContent as C; + + for c in &ty.content { + match c { + C::Annotation(_) => (), + C::Restriction(x) => self.apply_simple_type_restriction(x)?, + C::Union(x) => self.apply_union(x)?, + C::List(x) => self.apply_list(x)?, + } + } + + Ok(()) + } + + #[instrument(err, level = "trace", skip(self))] + fn apply_simple_type_restriction(&mut self, ty: &Restriction) -> Result<(), Error> { + use crate::schema::xs::RestrictionContent as C; + + let base = ty + .base + .as_ref() + .map(|base| { + let base = self.parse_qname(base)?; + + self.copy_base_type(&base)?; + + Ok(base) + }) + .transpose()?; + + for c in &ty.content { + match c { + C::Annotation(_) => (), + C::SimpleType(x) => self.apply_simple_type(x)?, + C::Facet(x) => self.apply_facet(x)?, + } + } + + if let Some(base) = base { + match &mut self.variant { + Some(SimpleTypeVariant::Reference(_)) => (), + Some(SimpleTypeVariant::Union(e)) => e.base = Base::Extension(base), + Some(SimpleTypeVariant::Enumeration(e)) => e.base = Base::Extension(base), + e => unreachable!("Unexpected type: {e:#?}"), + } + } + + Ok(()) + } + + #[instrument(err, level = "trace", skip(self))] + pub fn apply_facet(&mut self, ty: &Facet) -> Result<(), Error> { + match ty { + Facet::Enumeration(x) => self.apply_enumeration(x)?, + x => tracing::warn!("Unknown facet: {x:#?}"), + } + + Ok(()) + } + + #[instrument(err, level = "trace", skip(self))] + pub fn apply_enumeration(&mut self, ty: &FacetType) -> Result<(), Error> { + let name = Name::from(ty.value.trim().to_owned()); + let ident = Ident::new(name) + .with_ns(self.state.current_ns()) + .with_type(IdentType::Enumeration); + + let ei = Self::get_or_init_enumeration(&mut self.variant, self.fixed); + let var = ei.variants.find_or_insert(ident, VariantInfo::new); + var.use_ = Use::Required; + + Ok(()) + } + + #[instrument(err, level = "trace", skip(self))] + pub fn apply_union(&mut self, ty: &Union) -> Result<(), Error> { + let ui = Self::get_or_init_union(&mut self.variant, self.fixed); + + if let Some(types) = &ty.member_types { + for type_ in &types.0 { + let type_ = self.owner.parse_qname(type_)?; + ui.types.push(UnionTypeInfo::new(type_)); + } + } + + let ns = self.owner.state.current_ns(); + + for x in &ty.simple_type { + let name = self + .owner + .state + .name_builder() + .or(&x.name) + .auto_extend(false, true, self.owner.state) + .finish(); + let type_ = self.owner.create_simple_type(ns, Some(name), None, x)?; + ui.types.push(UnionTypeInfo::new(type_)); + } + + Ok(()) + } + + #[instrument(err, level = "trace", skip(self))] + fn apply_list(&mut self, ty: &List) -> Result<(), Error> { + let mut type_ = None; + + if let Some(s) = &ty.item_type { + type_ = Some(self.owner.parse_qname(s)?); + } + + if let Some(x) = &ty.simple_type { + let last_named_type = self.state.last_named_type(false).map(ToOwned::to_owned); + let name = self + .state + .name_builder() + .or(&x.name) + .or_else(|| from_utf8(ty.item_type.as_ref()?.local_name()).ok()) + .or_else(|| { + let s = last_named_type?; + let s = s.as_str(); + let s = s.strip_suffix("Type").unwrap_or(s); + let s = format!("{s}Item"); + + Some(Name::from(s)) + }) + .finish(); + let ns = self.owner.state.current_ns(); + type_ = Some(self.owner.create_simple_type(ns, Some(name), None, x)?); + } + + if let Some(type_) = type_ { + let ti = Self::get_or_init_reference( + &mut self.variant, + self.fixed, + ReferenceInfo::new(type_.clone()), + ); + ti.type_ = type_; + ti.min_occurs = 0; + ti.max_occurs = MaxOccurs::Unbounded; + + Ok(()) + } else { + Ok(()) + } + } + + fn copy_base_type(&mut self, base: &Ident) -> Result<(), Error> { + self.fixed = false; + + let base = self.owner.get_simple_type_variant(base)?; + + tracing::debug!("{base:#?}"); + + let mut base = base.clone(); + + if let SimpleTypeVariant::Enumeration(ei) = &mut base { + ei.variants.clear(); + } + + self.variant = Some(base); + + tracing::debug!("{:#?}", self.variant); + + Ok(()) + } +} + +impl<'schema, 'state> Deref for SimpleTypeBuilder<'_, 'schema, 'state> { + type Target = SchemaInterpreter<'schema, 'state>; + + fn deref(&self) -> &Self::Target { + self.owner + } +} + +impl DerefMut for SimpleTypeBuilder<'_, '_, '_> { + fn deref_mut(&mut self) -> &mut Self::Target { + self.owner + } +} diff --git a/src/interpreter/mod.rs b/src/interpreter/mod.rs index 0f3f57d0..dc111cd5 100644 --- a/src/interpreter/mod.rs +++ b/src/interpreter/mod.rs @@ -1,10 +1,10 @@ //! The `interpreter` module contains the schema [`Interpreter`] and all related types. +mod builders; mod error; mod name_builder; mod schema; mod state; -mod variant_builder; use std::fmt::Debug; @@ -12,8 +12,8 @@ use crate::config::Namespace; use crate::schema::xs::ProcessContentsType; use crate::schema::{MaxOccurs, Schemas}; use crate::types::{ - AnyAttributeInfo, AnyInfo, BuildInInfo, ComplexInfo, GroupInfo, Ident, Module, Name, - ReferenceInfo, Type, TypeVariant, Types, + AnyAttributeInfo, AnyInfo, BuildInInfo, ComplexInfo, ComplexType, ComplexTypeVariant, + GroupInfo, Ident, Module, Name, ReferenceInfo, SimpleType, Type, Types, }; pub use error::Error; @@ -21,7 +21,6 @@ use tracing::instrument; use self::schema::SchemaInterpreter; use self::state::{Node, State}; -use self::variant_builder::VariantBuilder; /// The [`Interpreter`] is used to interpret the XML schema information. /// @@ -68,13 +67,42 @@ impl<'a> Interpreter<'a> { /// /// Returns a suitable [`Error`] if the operation was not successful. #[instrument(err, level = "trace", skip(self))] - pub fn with_typedef(mut self, ident: I, type_: T) -> Result + pub fn with_typedef_simple(mut self, ident: I, type_: T) -> Result where I: Into + Debug, T: Into + Debug, { - self.state - .add_type(ident, ReferenceInfo::new(type_), true)?; + self.state.add_type( + ident, + SimpleType::new(crate::types::SimpleTypeVariant::Reference( + ReferenceInfo::new(type_), + )), + true, + )?; + + Ok(self) + } + + /// Add a simple type definition to the resulting [`Types`] structure using + /// `ident` as identifier for the new type and `type_` as target type for the + /// type definition. + /// + /// # Errors + /// + /// Returns a suitable [`Error`] if the operation was not successful. + #[instrument(err, level = "trace", skip(self))] + pub fn with_typedef_complex(mut self, ident: I, type_: T) -> Result + where + I: Into + Debug, + T: Into + Debug, + { + self.state.add_type( + ident, + ComplexType::new(crate::types::ComplexTypeVariant::Reference( + ReferenceInfo::new(type_), + )), + true, + )?; Ok(self) } @@ -88,8 +116,11 @@ impl<'a> Interpreter<'a> { pub fn with_buildin_types(mut self) -> Result { macro_rules! add { ($ident:ident, $type:ident) => { - self.state - .add_type(Ident::$ident, BuildInInfo::$type, true)?; + self.state.add_type( + Ident::$ident, + SimpleType::new(crate::types::SimpleTypeVariant::BuildIn(BuildInInfo::$type)), + true, + )?; }; } @@ -133,7 +164,9 @@ impl<'a> Interpreter<'a> { ($ns:ident, $src:expr, $dst:ident) => { self.state.add_type( Ident::type_($src).with_ns(Some($ns)), - ReferenceInfo::new(Ident::$dst), + SimpleType::new(crate::types::SimpleTypeVariant::Reference( + ReferenceInfo::new(Ident::$dst), + )), true, )?; }; @@ -142,9 +175,11 @@ impl<'a> Interpreter<'a> { ($ns:ident, $src:expr, $dst:ident) => { self.state.add_type( Ident::type_($src).with_ns(Some($ns)), - ReferenceInfo::new(Ident::$dst) - .min_occurs(0) - .max_occurs(MaxOccurs::Unbounded), + SimpleType::new(crate::types::SimpleTypeVariant::Reference( + ReferenceInfo::new(Ident::$dst) + .min_occurs(0) + .max_occurs(MaxOccurs::Unbounded), + )), true, )?; }; @@ -232,7 +267,7 @@ impl<'a> Interpreter<'a> { // content type let content_name = self.state.name_builder().shared_name("Content").finish(); let content_ident = Ident::new(content_name).with_ns(Some(xs)); - let content_variant = TypeVariant::Sequence(GroupInfo { + let content_variant = ComplexTypeVariant::Sequence(GroupInfo { any: Some(AnyInfo { min_occurs: Some(0), max_occurs: Some(MaxOccurs::Unbounded), @@ -241,13 +276,13 @@ impl<'a> Interpreter<'a> { }), ..Default::default() }); - let content_type = Type::new(content_variant); + let content_type = ComplexType::new(content_variant); self.state .add_type(content_ident.clone(), content_type, true)?; // xs:anyType let ident = Ident::type_("anyType").with_ns(Some(xs)); - let variant = TypeVariant::ComplexType(ComplexInfo { + let variant = ComplexTypeVariant::ComplexType(ComplexInfo { content: Some(content_ident), min_occurs: 1, max_occurs: MaxOccurs::Bounded(1), @@ -257,7 +292,7 @@ impl<'a> Interpreter<'a> { }), ..Default::default() }); - let type_ = Type::new(variant); + let type_ = ComplexType::new(variant); self.state.add_type(ident, type_, true)?; Ok(self) diff --git a/src/interpreter/schema.rs b/src/interpreter/schema.rs index 9c7161a5..87b44ab4 100644 --- a/src/interpreter/schema.rs +++ b/src/interpreter/schema.rs @@ -8,21 +8,21 @@ use crate::schema::xs::{ SchemaContent, SimpleBaseType, }; use crate::schema::{Namespace, NamespaceId, QName, Schemas}; -use crate::types::{Ident, IdentType, Name, Type, TypeVariant}; +use crate::types::{ComplexTypeVariant, Ident, IdentType, Name, SimpleTypeVariant, Type}; -use super::{Error, Node, State, VariantBuilder}; +use super::{builders, Error, Node, State}; #[derive(Debug)] -pub(super) struct SchemaInterpreter<'schema, 'state> { - pub(super) state: &'state mut State<'schema>, - pub(super) schema: &'schema Schema, - pub(super) schemas: &'schema Schemas, +pub(crate) struct SchemaInterpreter<'schema, 'state> { + pub state: &'state mut State<'schema>, + pub schema: &'schema Schema, + pub schemas: &'schema Schemas, } impl<'schema, 'state> SchemaInterpreter<'schema, 'state> { #[allow(clippy::unnecessary_literal_unwrap)] #[instrument(level = "trace", skip(state, schema, schemas))] - pub(super) fn process( + pub fn process( state: &'state mut State<'schema>, schema: &'schema Schema, schemas: &'schema Schemas, @@ -66,10 +66,10 @@ impl<'schema, 'state> SchemaInterpreter<'schema, 'state> { this.create_attribute(target_namespace, None, x)?; } SchemaContent::SimpleType(x) => { - this.create_simple_type(target_namespace, None, x)?; + this.create_simple_type(target_namespace, None, None, x)?; } SchemaContent::ComplexType(x) => { - this.create_complex_type(target_namespace, None, x)?; + this.create_complex_type(target_namespace, None, None, x)?; } } } @@ -82,7 +82,7 @@ impl<'schema, 'state> SchemaInterpreter<'schema, 'state> { impl SchemaInterpreter<'_, '_> { #[instrument(level = "trace", skip(self))] - pub(super) fn get_element_mut(&mut self, ident: &Ident) -> Result<&mut Type, Error> { + pub(crate) fn get_element_mut(&mut self, ident: &Ident) -> Result<&mut Type, Error> { if !self.state.types.contains_key(ident) { let ty = self .find_element(ident.clone()) @@ -96,64 +96,46 @@ impl SchemaInterpreter<'_, '_> { } #[instrument(level = "trace", skip(self))] - pub(super) fn get_simple_type_variant(&mut self, ident: &Ident) -> Result<&TypeVariant, Error> { + pub(crate) fn get_simple_type_variant( + &mut self, + ident: &Ident, + ) -> Result<&mut SimpleTypeVariant, Error> { if !self.state.types.contains_key(ident) { let ty = self .find_simple_type(ident.clone()) .ok_or_else(|| Error::UnknownType(ident.clone()))?; - let new_ident = self.create_simple_type(ident.ns, None, ty)?; + + let new_ident = self.create_simple_type(ident.ns, None, None, ty)?; crate::assert_eq!(ident, &new_ident); } - match self.state.types.get_variant(ident) { - None - | Some( - TypeVariant::ComplexType(_) - | TypeVariant::All(_) - | TypeVariant::Choice(_) - | TypeVariant::Sequence(_) - | TypeVariant::Dynamic(_), - ) => Err(Error::UnknownType(ident.clone())), - Some( - ty @ (TypeVariant::Enumeration(_) - | TypeVariant::BuildIn(_) - | TypeVariant::Union(_) - | TypeVariant::Reference(_)), - ) => Ok(ty), - } + self.state + .types + .get_simple_type_mut(ident) + .map(|ty| &mut ty.variant) + .ok_or(Error::UnknownType(ident.clone())) } #[instrument(level = "trace", skip(self))] - pub(super) fn get_complex_type_variant( + pub(crate) fn get_complex_type_variant( &mut self, ident: &Ident, - ) -> Result<&TypeVariant, Error> { + ) -> Result<&mut ComplexTypeVariant, Error> { if !self.state.types.contains_key(ident) { let ty = self .find_complex_type(ident.clone()) .ok_or_else(|| Error::UnknownType(ident.clone()))?; - let new_ident = self.create_complex_type(ident.ns, None, ty)?; + let new_ident = self.create_complex_type(ident.ns, None, None, ty)?; crate::assert_eq!(ident, &new_ident); } - match self.state.types.get_variant(ident) { - None - | Some( - TypeVariant::Enumeration(_) - | TypeVariant::BuildIn(_) - | TypeVariant::Union(_) - | TypeVariant::Reference(_), - ) => Err(Error::UnknownType(ident.clone())), - Some( - ty @ (TypeVariant::ComplexType(_) - | TypeVariant::All(_) - | TypeVariant::Choice(_) - | TypeVariant::Sequence(_) - | TypeVariant::Dynamic(_)), - ) => Ok(ty), - } + self.state + .types + .get_complex_type_mut(ident) + .map(|ty| &mut ty.variant) + .ok_or(Error::UnknownType(ident.clone())) } } @@ -161,7 +143,7 @@ impl SchemaInterpreter<'_, '_> { impl SchemaInterpreter<'_, '_> { #[instrument(err, level = "trace", skip(self))] - pub(super) fn create_element( + pub(crate) fn create_element( &mut self, ns: Option, name: Option, @@ -173,11 +155,17 @@ impl SchemaInterpreter<'_, '_> { type_: IdentType::Element, }; - self.create_type(ident, |builder| builder.apply_element(ty)) + self.create_type(ident.clone(), move |owner| { + let mut builder = builders::ElementBuilder::new(owner); + builder.apply_element(ty)?; + let type_ = builder.finish()?; + + Ok(type_) + }) } #[instrument(err, level = "trace", skip(self))] - pub(super) fn create_attribute( + pub(crate) fn create_attribute( &mut self, ns: Option, name: Option, @@ -189,44 +177,64 @@ impl SchemaInterpreter<'_, '_> { type_: IdentType::Attribute, }; - self.create_type(ident.clone(), |builder| builder.apply_attribute(ty)) + self.create_type(ident.clone(), move |owner| { + let mut builder = builders::AttributeTypeBuilder::new(owner); + builder.apply_attribute(ty)?; + let type_ = builder.finish()?; + + Ok(type_) + }) } #[instrument(err, level = "trace", skip(self))] - pub(super) fn create_simple_type( + pub(crate) fn create_simple_type( &mut self, ns: Option, name: Option, + ident_type: Option, ty: &SimpleBaseType, ) -> Result { let ident = Ident { ns, name: self.state.name_builder().or(name).or(&ty.name).finish(), - type_: IdentType::Type, + type_: ident_type.unwrap_or(IdentType::Type), }; - self.create_type(ident, |builder| builder.apply_simple_type(ty)) + self.create_type(ident.clone(), move |owner| { + let mut builder = builders::SimpleTypeBuilder::new(owner); + builder.apply_simple_type(ty)?; + let type_ = builder.finish()?; + + Ok(type_) + }) } #[instrument(err, level = "trace", skip(self))] - pub(super) fn create_complex_type( + pub(crate) fn create_complex_type( &mut self, ns: Option, name: Option, + ident_type: Option, ty: &ComplexBaseType, ) -> Result { let ident = Ident { ns, name: self.state.name_builder().or(name).or(&ty.name).finish(), - type_: IdentType::Type, + type_: ident_type.unwrap_or(IdentType::Type), }; - self.create_type(ident, |builder| builder.apply_complex_type(ty)) + self.create_type(ident.clone(), move |owner| { + let mut builder = builders::ComplexTypeBuilder::new(owner); + builder.apply_complex_type(ty)?; + let type_ = builder.finish()?; + + Ok(type_) + }) } - pub(super) fn create_type(&mut self, ident: Ident, mut f: F) -> Result + pub(super) fn create_type(&mut self, ident: Ident, f: F) -> Result where - F: FnMut(&mut VariantBuilder<'_, '_, '_>) -> Result<(), Error>, + F: FnOnce(&mut SchemaInterpreter<'_, '_>) -> Result, { if self.state.types.types.contains_key(&ident) || self @@ -240,8 +248,7 @@ impl SchemaInterpreter<'_, '_> { self.state.type_stack.push(Some(ident)); - let mut builder = VariantBuilder::new(self); - let type_ = f(&mut builder).and_then(|()| builder.finish()); + let type_ = f(self); let ident = self.state.type_stack.pop().unwrap().unwrap(); diff --git a/src/misc.rs b/src/misc.rs index 1f8c686f..7bbc7f09 100644 --- a/src/misc.rs +++ b/src/misc.rs @@ -6,7 +6,7 @@ use std::io::Error as IoError; use anyhow::Error as AnyError; use thiserror::Error; -use crate::types::{ElementMode, Ident, Type, TypeVariant, Types}; +use crate::types::{ComplexTypeVariant, ElementMode, Ident, SimpleTypeVariant, Type, Types}; use crate::{GeneratorError, InterpreterError, OptimizerError, ParserError}; /// Trait that adds namespace information to a type. @@ -172,20 +172,15 @@ impl<'a> TypesPrinter<'a> { } } - #[allow(clippy::too_many_lines)] - fn print_type( + #[allow(clippy::too_many_lines, clippy::unused_self)] + fn print_simple_type( &self, f: &mut Formatter<'_>, s: &mut State, ident: &Ident, - ty: &Type, + display_name: Option<&str>, + variant: &SimpleTypeVariant, ) -> FmtResult { - macro_rules! indent { - ($( $tt:tt )*) => {{ - write!(f, "{0:1$}", "", 4 * s.level)?; - write!(f, $( $tt )*)?; - }}; - } macro_rules! indentln { ($( $tt:tt )*) => {{ write!(f, "{0:1$}", "", 4 * s.level)?; @@ -193,29 +188,23 @@ impl<'a> TypesPrinter<'a> { }}; } - if !s.visit.insert(ident.clone()) { - writeln!(f, "LOOP DETECTED ({})", ident.name)?; - - return Ok(()); - } - - match &ty.variant { - TypeVariant::BuildIn(x) => { + match &variant { + SimpleTypeVariant::BuildIn(x) => { writeln!(f, "{}: BuildIn", ident)?; s.level += 1; - indentln!("display_name={:?}", &ty.display_name); + indentln!("display_name={:?}", &display_name); indentln!("type={x:?}"); s.level -= 1; } - TypeVariant::Union(x) => { + SimpleTypeVariant::Union(x) => { writeln!(f, "{}: Union", ident)?; s.level += 1; - indentln!("display_name={:?}", &ty.display_name); + indentln!("display_name={:?}", &display_name); indentln!("base={}", x.base); indentln!("types"); @@ -227,62 +216,104 @@ impl<'a> TypesPrinter<'a> { s.level -= 2; } - TypeVariant::Reference(x) => { + SimpleTypeVariant::Reference(x) => { writeln!(f, "{}: Reference", ident)?; s.level += 1; - indentln!("display_name={:?}", &ty.display_name); + indentln!("display_name={:?}", &display_name); indentln!("min={}", x.min_occurs); indentln!("max={:?}", x.max_occurs); indentln!("type={}", x.type_); s.level -= 1; } - TypeVariant::Dynamic(x) => { - writeln!(f, "{}: Dynamic", ident)?; + SimpleTypeVariant::Enumeration(x) => { + writeln!(f, "{}: Enumeration", ident)?; s.level += 1; - indentln!("display_name={:?}", &ty.display_name); - indentln!("types"); + indentln!("display_name={:?}", &display_name); + indentln!("base={}", x.base); + indentln!("variants"); s.level += 1; - for ty in &*x.derived_types { - indentln!("{}", ty); + for var in &*x.variants { + indentln!("{}={:?}", var.ident.name, var.use_); } s.level -= 2; } - TypeVariant::Enumeration(x) => { - writeln!(f, "{}: Enumeration", ident)?; + } + + Ok(()) + } + + #[allow(clippy::too_many_lines)] + fn print_complex_type( + &self, + f: &mut Formatter<'_>, + s: &mut State, + ident: &Ident, + display_name: Option<&str>, + variant: &ComplexTypeVariant, + ) -> FmtResult { + macro_rules! indent { + ($( $tt:tt )*) => {{ + write!(f, "{0:1$}", "", 4 * s.level)?; + write!(f, $( $tt )*)?; + }}; + } + macro_rules! indentln { + ($( $tt:tt )*) => {{ + write!(f, "{0:1$}", "", 4 * s.level)?; + writeln!(f, $( $tt )*)?; + }}; + } + + match &variant { + ComplexTypeVariant::Reference(x) => { + writeln!(f, "{}: Reference", ident)?; s.level += 1; - indentln!("display_name={:?}", &ty.display_name); - indentln!("base={}", x.base); - indentln!("variants"); + indentln!("display_name={:?}", &display_name); + indentln!("min={}", x.min_occurs); + indentln!("max={:?}", x.max_occurs); + indentln!("type={}", x.type_); + + s.level -= 1; + } + ComplexTypeVariant::Dynamic(x) => { + writeln!(f, "{}: Dynamic", ident)?; s.level += 1; - for var in &*x.variants { - indentln!("{}={:?}", var.ident.name, var.use_); + indentln!("display_name={:?}", &display_name); + indentln!("types"); + + s.level += 1; + + for ty in &*x.derived_types { + indentln!("{}", ty); } s.level -= 2; } - TypeVariant::All(x) | TypeVariant::Choice(x) | TypeVariant::Sequence(x) => { - match &ty.variant { - TypeVariant::All(_) => writeln!(f, "{}: All", ident)?, - TypeVariant::Choice(_) => writeln!(f, "{}: Choice", ident)?, - TypeVariant::Sequence(_) => writeln!(f, "{}: Sequence", ident)?, + ComplexTypeVariant::All(x) + | ComplexTypeVariant::Choice(x) + | ComplexTypeVariant::Sequence(x) => { + match &variant { + ComplexTypeVariant::All(_) => writeln!(f, "{}: All", ident)?, + ComplexTypeVariant::Choice(_) => writeln!(f, "{}: Choice", ident)?, + ComplexTypeVariant::Sequence(_) => writeln!(f, "{}: Sequence", ident)?, _ => (), } s.level += 1; - indentln!("display_name={:?}", &ty.display_name); + indentln!("display_name={:?}", &display_name); if let Some(x) = &x.any { indentln!("any"); @@ -333,12 +364,12 @@ impl<'a> TypesPrinter<'a> { s.level -= 1; } - TypeVariant::ComplexType(x) => { + ComplexTypeVariant::ComplexType(x) => { writeln!(f, "{}: ComplexType", ident)?; s.level += 1; - indentln!("display_name={:?}", &ty.display_name); + indentln!("display_name={:?}", &display_name); indentln!("base={}", x.base); indentln!("min_occurs={}", x.min_occurs); indentln!("max_occurs={:?}", x.max_occurs); @@ -391,6 +422,35 @@ impl<'a> TypesPrinter<'a> { s.level -= 1; } + ComplexTypeVariant::SimpleType(simple_type_variant) => { + self.print_simple_type(f, s, ident, display_name, simple_type_variant)?; + } + } + + Ok(()) + } + + #[allow(clippy::too_many_lines)] + fn print_type( + &self, + f: &mut Formatter<'_>, + s: &mut State, + ident: &Ident, + ty: &Type, + ) -> FmtResult { + if !s.visit.insert(ident.clone()) { + writeln!(f, "LOOP DETECTED ({})", ident.name)?; + + return Ok(()); + } + + match &ty { + Type::SimpleType(ty) => { + self.print_simple_type(f, s, ident, ty.display_name.as_deref(), &ty.variant)?; + } + Type::ComplexType(ty) => { + self.print_complex_type(f, s, ident, ty.display_name.as_deref(), &ty.variant)?; + } } s.visit.remove(ident); diff --git a/src/optimizer/dynamic_to_choice.rs b/src/optimizer/dynamic_to_choice.rs index fadffa76..bf8c3dc1 100644 --- a/src/optimizer/dynamic_to_choice.rs +++ b/src/optimizer/dynamic_to_choice.rs @@ -1,5 +1,6 @@ use crate::types::{ - ComplexInfo, ElementInfo, ElementMode, GroupInfo, Ident, Type, TypeVariant, Types, VecHelper, + ComplexInfo, ComplexTypeVariant, ElementInfo, ElementMode, GroupInfo, Ident, Type, + TypeDescriptor, Types, VecHelper, }; use super::TypeTransformer; @@ -37,7 +38,13 @@ impl TypeTransformer for ConvertDynamicToChoice { let idents = types .iter() .filter_map(|(ident, ty)| { - if matches!(&ty.variant, TypeVariant::Dynamic(_)) { + if matches!( + &ty, + Type::ComplexType(TypeDescriptor { + variant: ComplexTypeVariant::Dynamic(_), + .. + }) + ) { Some(ident) } else { None @@ -51,7 +58,15 @@ impl TypeTransformer for ConvertDynamicToChoice { let content_ident = Ident::new(content_name).with_ns(ident.ns); let type_ = types.get_mut(&ident).unwrap(); - let TypeVariant::Dynamic(x) = &mut type_.variant else { + let Type::ComplexType(TypeDescriptor { + variant: variant @ ComplexTypeVariant::Dynamic(_), + .. + }) = type_ + else { + crate::unreachable!(); + }; + + let ComplexTypeVariant::Dynamic(x) = variant else { crate::unreachable!(); }; @@ -62,7 +77,7 @@ impl TypeTransformer for ConvertDynamicToChoice { }); } - type_.variant = TypeVariant::ComplexType(ComplexInfo { + *variant = ComplexTypeVariant::ComplexType(ComplexInfo { content: Some(content_ident.clone()), is_dynamic: true, ..Default::default() @@ -70,7 +85,9 @@ impl TypeTransformer for ConvertDynamicToChoice { match types.entry(content_ident) { Entry::Vacant(e) => { - e.insert(Type::new(TypeVariant::Choice(si))); + e.insert(Type::ComplexType(TypeDescriptor::new( + ComplexTypeVariant::Choice(si), + ))); } Entry::Occupied(_) => crate::unreachable!(), } diff --git a/src/optimizer/empty_enums.rs b/src/optimizer/empty_enums.rs index eea5fd21..715071de 100644 --- a/src/optimizer/empty_enums.rs +++ b/src/optimizer/empty_enums.rs @@ -1,4 +1,4 @@ -use crate::types::{Name, ReferenceInfo, TypeVariant, Types}; +use crate::types::{Name, ReferenceInfo, SimpleTypeVariant, Types}; use super::TypeTransformer; @@ -29,8 +29,8 @@ impl TypeTransformer for RemoveEmptyEnumVariants { fn transform(&self, types: &mut Types) -> Result<(), super::Error> { tracing::debug!("remove_empty_enum_variants"); - for type_ in types.types.values_mut() { - if let TypeVariant::Enumeration(x) = &mut type_.variant { + for (_, variant) in types.simple_types_iter_mut() { + if let SimpleTypeVariant::Enumeration(x) = variant { x.variants .retain(|x| !matches!(&x.ident.name, Name::Named(x) if x.is_empty())); } @@ -72,11 +72,11 @@ impl TypeTransformer for RemoveEmptyEnums { fn transform(&self, types: &mut Types) -> Result<(), super::Error> { tracing::debug!("remove_empty_enums"); - for type_ in types.types.values_mut() { - if let TypeVariant::Enumeration(x) = &mut type_.variant { + for (_, variant) in types.simple_types_iter_mut() { + if let SimpleTypeVariant::Enumeration(x) = variant { if x.variants.is_empty() { if let Some(base) = x.base.as_ident() { - type_.variant = TypeVariant::Reference(ReferenceInfo::new(base.clone())); + *variant = SimpleTypeVariant::Reference(ReferenceInfo::new(base.clone())); } } } diff --git a/src/optimizer/empty_unions.rs b/src/optimizer/empty_unions.rs index 9e6be294..cb6a2910 100644 --- a/src/optimizer/empty_unions.rs +++ b/src/optimizer/empty_unions.rs @@ -1,6 +1,6 @@ use std::collections::HashSet; -use crate::types::{ReferenceInfo, TypeVariant, Types}; +use crate::types::{ReferenceInfo, SimpleTypeVariant, Types}; use super::TypeTransformer; @@ -36,8 +36,8 @@ impl TypeTransformer for RemoveDuplicateUnionVariants { let typedefs = crate::optimizer::TypedefMap::new(types); - for type_ in types.types.values_mut() { - if let TypeVariant::Union(x) = &mut type_.variant { + for (_, variant) in types.simple_types_iter_mut() { + if let SimpleTypeVariant::Union(x) = variant { let mut i = 0; let mut types_ = HashSet::new(); @@ -84,12 +84,12 @@ impl TypeTransformer for RemoveEmptyUnions { fn transform(&self, types: &mut Types) -> Result<(), super::Error> { tracing::debug!("remove_empty_unions"); - for type_ in types.types.values_mut() { - if let TypeVariant::Union(x) = &type_.variant { + for (_, variant) in types.simple_types_iter_mut() { + if let SimpleTypeVariant::Union(x) = variant { if x.types.len() <= 1 { let base = x.types.first().map(|x| &x.type_).or(x.base.as_ident()); if let Some(base) = base { - type_.variant = TypeVariant::Reference(ReferenceInfo::new(base.clone())); + *variant = SimpleTypeVariant::Reference(ReferenceInfo::new(base.clone())); } } } diff --git a/src/optimizer/flatten_complex_type.rs b/src/optimizer/flatten_complex_type.rs index 2225447e..1b69d3e7 100644 --- a/src/optimizer/flatten_complex_type.rs +++ b/src/optimizer/flatten_complex_type.rs @@ -1,6 +1,6 @@ use crate::{ schema::{MaxOccurs, MinOccurs}, - types::{ElementInfo, ElementMode, GroupInfo, Ident, Type, TypeVariant, Types}, + types::{ComplexTypeVariant, TypeDescriptor, ElementInfo, ElementMode, GroupInfo, Ident, Type, Types}, }; use super::{Error, TypeTransformer}; @@ -36,9 +36,9 @@ impl TypeTransformer for FlattenComplexTypes { let idents = types - .iter() - .filter_map(|(ident, type_)| { - if matches!(&type_.variant, TypeVariant::ComplexType(ci) if ci.has_complex_content(types)) { + .complex_types_iter() + .filter_map(|(ident, variant)| { + if matches!(&variant, ComplexTypeVariant::ComplexType(ci) if ci.has_complex_content(types)) { Some(ident) } else { None @@ -59,11 +59,11 @@ impl FlattenComplexTypes { fn flatten_complex_type( types: &mut Types, ident: Ident) -> Result<(), Error> { tracing::debug!("flatten_complex_type(ident={ident:?})"); - let Some(ty) = types.get(&ident) else { + let Some(ty) = types.get_complex_type(&ident) else { return Err(Error::UnknownType(ident)); }; - let TypeVariant::ComplexType(ci) = &ty.variant else { + let ComplexTypeVariant::ComplexType(ci) = &ty.variant else { return Err(Error::ExpectedComplexType(ident)); }; @@ -78,14 +78,14 @@ impl FlattenComplexTypes { if ctx.count > 1 { let variant = match ctx.mode { Mode::Unknown => unreachable!(), - Mode::Sequence => TypeVariant::Sequence(ctx.info), - Mode::Mixed | Mode::Choice => TypeVariant::Choice(ctx.info), + Mode::Sequence => ComplexTypeVariant::Sequence(ctx.info), + Mode::Mixed | Mode::Choice => ComplexTypeVariant::Choice(ctx.info), }; - let type_ = Type::new(variant); + let type_ = Type::ComplexType(TypeDescriptor::new(variant)); types.insert(content_ident, type_); - if let Some(TypeVariant::ComplexType(ci)) = types.get_variant_mut(&ident) { + if let Some(ComplexTypeVariant::ComplexType(ci)) = types.get_complex_type_mut(&ident).map(|t| &mut t.variant) { ci.min_occurs *= ctx.occurs.min; ci.max_occurs *= ctx.occurs.max; } @@ -101,17 +101,17 @@ impl FlattenComplexTypes { max: MaxOccurs, ctx: &mut Context, ) { - let Some(type_) = types.get(ident) else { + let Some(type_) = types.get_complex_type(ident) else { return; }; let si = match &type_.variant { - TypeVariant::Choice(si) => { + ComplexTypeVariant::Choice(si) => { ctx.set_mode(Mode::Choice); si } - TypeVariant::All(si) | TypeVariant::Sequence(si) => { + ComplexTypeVariant::All(si) | ComplexTypeVariant::Sequence(si) => { if max > MaxOccurs::Bounded(1) { ctx.set_mode(Mode::Choice); } else { @@ -120,7 +120,7 @@ impl FlattenComplexTypes { si } - TypeVariant::Reference(ti) if ti.is_single() => { + ComplexTypeVariant::Reference(ti) if ti.is_single() => { Self::flatten_complex_type_impl( types, &ti.type_, @@ -260,15 +260,16 @@ impl Default for ContextOccurs { #[cfg(test)] mod tests { use crate::{ - optimizer::{flatten_complex_type::FlattenComplexTypes, TypeTransformer}, schema::MaxOccurs, types::{ElementInfo, ElementMode, ElementsInfo, Ident, Type, TypeVariant, Types} + optimizer::{flatten_complex_type::FlattenComplexTypes, TypeTransformer}, schema::MaxOccurs, types::{ComplexTypeVariant, ElementInfo, ElementMode, ElementsInfo, Ident, Type, TypeDescriptor, Types} }; + macro_rules! make_type { ($types:expr, $name:literal, $type:ident $( $rest:tt )*) => {{ - let mut variant = TypeVariant::$type(Default::default()); - let TypeVariant::$type(info) = &mut variant else { unreachable!(); }; + let mut variant = ComplexTypeVariant::$type(Default::default()); + let ComplexTypeVariant::$type(info) = &mut variant else { unreachable!(); }; make_type!(__init info $type $( $rest )*); - let ty = Type::new(variant); + let ty = Type::ComplexType(TypeDescriptor::::new(variant)); $types.insert(Ident::type_($name), ty); }}; (__init $info:ident ComplexType($name:literal) $(,)? ) => { @@ -325,13 +326,13 @@ mod tests { macro_rules! assert_type { ($types:expr, $main_ident:literal, $content_type:ident($content_ident:literal)) => {{ - let main = $types.get_variant(&Ident::type_($main_ident)).unwrap(); - let content = $types.get_variant(&Ident::type_($content_ident)).unwrap(); + let main = $types.get_complex_type(&Ident::type_($main_ident)).unwrap(); + let content = $types.get_complex_type(&Ident::type_($content_ident)).unwrap(); - let TypeVariant::ComplexType(main) = main else { + let ComplexTypeVariant::ComplexType(main) = &main.variant else { panic!("Wrong type"); }; - let TypeVariant::$content_type(content) = content else { + let ComplexTypeVariant::$content_type(content) = &content.variant else { panic!("Wrong type"); }; diff --git a/src/optimizer/flatten_unions.rs b/src/optimizer/flatten_unions.rs index 2dd208f3..a7467873 100644 --- a/src/optimizer/flatten_unions.rs +++ b/src/optimizer/flatten_unions.rs @@ -1,4 +1,4 @@ -use crate::types::{Ident, TypeVariant, Types, UnionInfo, UnionTypeInfo}; +use crate::types::{Ident, SimpleTypeVariant, Types, UnionInfo, UnionTypeInfo}; use super::{Error, TypeTransformer}; @@ -20,9 +20,9 @@ impl TypeTransformer for FlattenUnions { tracing::debug!("flatten_unions"); let idents = types - .iter() - .filter_map(|(ident, type_)| { - if matches!(&type_.variant, TypeVariant::Union(_)) { + .simple_types_iter() + .filter_map(|(ident, variant)| { + if matches!(&variant, SimpleTypeVariant::Union(_)) { Some(ident) } else { None @@ -66,11 +66,11 @@ impl FlattenUnions { pub fn flatten_union(&self, types: &mut Types, ident: Ident) -> Result<(), Error> { tracing::debug!("flatten_union(ident={ident:?})"); - let Some(ty) = types.get(&ident) else { + let Some(ty) = types.get_simple_type(&ident) else { return Err(Error::UnknownType(ident)); }; - let TypeVariant::Union(ui) = &ty.variant else { + let SimpleTypeVariant::Union(ui) = &ty.variant else { return Err(Error::ExpectedUnion(ident)); }; @@ -84,8 +84,8 @@ impl FlattenUnions { if info.count > 1 { info.info.base = ui.base.clone(); - let ty = types.get_mut(&ident).unwrap(); - ty.variant = TypeVariant::Union(info.info); + let ty = types.get_simple_type_mut(&ident).unwrap(); + ty.variant = SimpleTypeVariant::Union(info.info); } Ok(()) @@ -97,18 +97,18 @@ impl FlattenUnions { display_name: Option<&str>, next: &mut FlattenUnionInfo, ) { - let Some(type_) = types.get(ident) else { + let Some(type_) = types.get_simple_type(ident) else { return; }; match &type_.variant { - TypeVariant::Union(x) => { + SimpleTypeVariant::Union(x) => { next.count += 1; for t in &*x.types { Self::flatten_union_impl(types, &t.type_, t.display_name.as_deref(), next); } } - TypeVariant::Reference(x) if x.is_single() => { + SimpleTypeVariant::Reference(x) if x.is_single() => { Self::flatten_union_impl(types, &x.type_, display_name, next); } _ => { diff --git a/src/optimizer/merge_choice_cardinality.rs b/src/optimizer/merge_choice_cardinality.rs index ac9d7116..e06e1db4 100644 --- a/src/optimizer/merge_choice_cardinality.rs +++ b/src/optimizer/merge_choice_cardinality.rs @@ -1,6 +1,6 @@ use crate::{ schema::MaxOccurs, - types::{Ident, TypeVariant, Types}, + types::{ComplexTypeVariant, Ident, Types}, }; use super::{Error, TypeTransformer}; @@ -20,9 +20,9 @@ impl TypeTransformer for MergeChoiceCardinalities { let idents = types - .iter() - .filter_map(|(ident, type_)| { - if matches!(&type_.variant, TypeVariant::ComplexType(ci) if ci.has_complex_choice_content(types)) { + .complex_types_iter() + .filter_map(|(ident, variant)| { + if matches!(&variant, ComplexTypeVariant::ComplexType(ci) if ci.has_complex_choice_content(types)) { Some(ident) } else { None @@ -71,11 +71,11 @@ impl MergeChoiceCardinalities { ) -> Result<(), Error> { tracing::debug!("merge_choice_cardinality(ident={ident:?})"); - let Some(ty) = types.get_variant(&ident) else { + let Some(ty) = types.get_complex_type(&ident).map(|a| &a.variant) else { return Err(Error::UnknownType(ident)); }; - let TypeVariant::ComplexType(ci) = ty else { + let ComplexTypeVariant::ComplexType(ci) = ty else { return Err(Error::ExpectedComplexType(ident)); }; @@ -83,7 +83,7 @@ impl MergeChoiceCardinalities { return Err(Error::MissingContentType(ident)); }; - let Some(TypeVariant::Choice(ci)) = types.get_variant_mut(&content_ident) else { + let Some(ComplexTypeVariant::Choice(ci)) = types.get_complex_type_mut(&content_ident).map(|a| &mut a.variant) else { return Err(Error::ExpectedComplexChoice(ident)); }; @@ -98,7 +98,7 @@ impl MergeChoiceCardinalities { element.max_occurs = MaxOccurs::Bounded(1); } - let Some(TypeVariant::ComplexType(ci)) = types.get_variant_mut(&ident) else { + let Some(ComplexTypeVariant::ComplexType(ci)) = types.get_complex_type_mut(&ident).map(|a| &mut a.variant) else { unreachable!(); }; diff --git a/src/optimizer/merge_enum_unions.rs b/src/optimizer/merge_enum_unions.rs index 850d8931..97112dcc 100644 --- a/src/optimizer/merge_enum_unions.rs +++ b/src/optimizer/merge_enum_unions.rs @@ -1,5 +1,6 @@ use crate::types::{ - EnumerationInfo, Ident, TypeVariant, Types, UnionInfo, UnionTypeInfo, VariantInfo, VecHelper, + EnumerationInfo, Ident, SimpleTypeVariant, Types, UnionInfo, UnionTypeInfo, VariantInfo, + VecHelper, }; use super::{Error, TypeTransformer}; @@ -17,9 +18,9 @@ impl TypeTransformer for MergeEnumUnions { tracing::debug!("merge_enum_unions"); let idents = types - .iter() - .filter_map(|(ident, type_)| { - if matches!(&type_.variant, TypeVariant::Union(_)) { + .simple_types_iter() + .filter_map(|(ident, variant)| { + if matches!(&variant, SimpleTypeVariant::Union(_)) { Some(ident) } else { None @@ -66,11 +67,11 @@ impl MergeEnumUnions { pub fn merge_enum_union(types: &mut Types, ident: Ident) -> Result<(), Error> { tracing::debug!("merge_enum_union(ident={ident:?})"); - let Some(variant) = types.get_variant(&ident) else { + let Some(variant) = types.get_simple_type(&ident).map(|x| &x.variant) else { return Err(Error::UnknownType(ident)); }; - let TypeVariant::Union(_) = variant else { + let SimpleTypeVariant::Union(_) = variant else { return Err(Error::ExpectedUnion(ident)); }; @@ -79,7 +80,7 @@ impl MergeEnumUnions { Self::merge_enum_union_impl(types, &ident, None, &mut next); if let Some(next) = next { - let ty = types.get_mut(&ident).unwrap(); + let ty = types.get_simple_type_mut(&ident).unwrap(); ty.variant = next; } @@ -90,23 +91,25 @@ impl MergeEnumUnions { types: &Types, ident: &Ident, display_name: Option<&str>, - next: &mut Option, + next: &mut Option, ) { - let Some(type_) = types.get_variant(ident) else { + let Some(type_) = types.get_simple_type(ident).map(|x| &x.variant) else { return; }; match type_ { - TypeVariant::Union(x) => { + SimpleTypeVariant::Union(x) => { for t in &*x.types { Self::merge_enum_union_impl(types, &t.type_, t.display_name.as_deref(), next); } } - TypeVariant::Enumeration(x) => { + SimpleTypeVariant::Enumeration(x) => { *next = match next.take() { - None => Some(TypeVariant::Enumeration(EnumerationInfo::default())), - Some(TypeVariant::Enumeration(ei)) => Some(TypeVariant::Enumeration(ei)), - Some(TypeVariant::Union(ui)) => { + None => Some(SimpleTypeVariant::Enumeration(EnumerationInfo::default())), + Some(SimpleTypeVariant::Enumeration(ei)) => { + Some(SimpleTypeVariant::Enumeration(ei)) + } + Some(SimpleTypeVariant::Union(ui)) => { let mut ei = EnumerationInfo::default(); for t in ui.types.0 { @@ -116,12 +119,12 @@ impl MergeEnumUnions { var.display_name = t.display_name; } - Some(TypeVariant::Enumeration(ei)) + Some(SimpleTypeVariant::Enumeration(ei)) } _ => crate::unreachable!(), }; - let Some(TypeVariant::Enumeration(ei)) = next else { + let Some(SimpleTypeVariant::Enumeration(ei)) = next else { crate::unreachable!(); }; @@ -132,22 +135,22 @@ impl MergeEnumUnions { new_var.display_name.clone_from(&var.display_name); } } - TypeVariant::Reference(x) if x.is_single() => { + SimpleTypeVariant::Reference(x) if x.is_single() => { Self::merge_enum_union_impl(types, &x.type_, display_name, next); } _ => { if next.is_none() { - *next = Some(TypeVariant::Union(UnionInfo::default())); + *next = Some(SimpleTypeVariant::Union(UnionInfo::default())); } match next { - Some(TypeVariant::Union(ui)) => { + Some(SimpleTypeVariant::Union(ui)) => { let mut ti = UnionTypeInfo::new(ident.clone()); ti.display_name = display_name.map(ToOwned::to_owned); ui.types.push(ti); } - Some(TypeVariant::Enumeration(ei)) => { + Some(SimpleTypeVariant::Enumeration(ei)) => { let var = ei.variants.find_or_insert(ident.clone(), |x| { VariantInfo::new(x).with_type(Some(ident.clone())) }); diff --git a/src/optimizer/misc/base_map.rs b/src/optimizer/misc/base_map.rs index ef3bada1..268f5468 100644 --- a/src/optimizer/misc/base_map.rs +++ b/src/optimizer/misc/base_map.rs @@ -1,6 +1,8 @@ use std::collections::HashMap; -use crate::types::{Base, Ident, TypeVariant, Types}; +use crate::types::{ + Base, ComplexTypeVariant, Ident, SimpleTypeVariant, Type, TypeDescriptor, Types, +}; #[derive(Debug)] pub(crate) struct BaseMap(HashMap); @@ -10,27 +12,42 @@ impl BaseMap { let mut ret = HashMap::new(); for (ident, type_) in &types.types { - match &type_.variant { - TypeVariant::Enumeration(ei) => { + match type_ { + Type::SimpleType(TypeDescriptor { + variant: SimpleTypeVariant::Enumeration(ei), + .. + }) => { if matches!( - ei.base.as_ident().and_then(|base| types.get_variant(base)), - Some(TypeVariant::Enumeration(_)) + ei.base + .as_ident() + .and_then(|base| types.get_simple_type(base).map(|a| &a.variant)), + Some(SimpleTypeVariant::Enumeration(_)) ) { ret.insert(ident.clone(), ei.base.clone()); } } - TypeVariant::Union(ei) => { + Type::SimpleType(TypeDescriptor { + variant: SimpleTypeVariant::Union(ei), + .. + }) => { if matches!( - ei.base.as_ident().and_then(|base| types.get_variant(base)), - Some(TypeVariant::Union(_)) + ei.base + .as_ident() + .and_then(|base| types.get_simple_type(base).map(|a| &a.variant)), + Some(SimpleTypeVariant::Union(_)) ) { ret.insert(ident.clone(), ei.base.clone()); } } - TypeVariant::ComplexType(ci) => { + Type::ComplexType(TypeDescriptor { + variant: ComplexTypeVariant::ComplexType(ci), + .. + }) => { if matches!( - ci.base.as_ident().and_then(|base| types.get_variant(base)), - Some(TypeVariant::ComplexType(_)) + ci.base + .as_ident() + .and_then(|base| types.get_complex_type(base).map(|a| &a.variant)), + Some(ComplexTypeVariant::ComplexType(_)) ) { ret.insert(ident.clone(), ci.base.clone()); } diff --git a/src/optimizer/misc/typedef_map.rs b/src/optimizer/misc/typedef_map.rs index 0c57823a..1891a682 100644 --- a/src/optimizer/misc/typedef_map.rs +++ b/src/optimizer/misc/typedef_map.rs @@ -1,6 +1,6 @@ use std::collections::HashMap; -use crate::types::{Ident, TypeVariant, Types}; +use crate::types::{ComplexTypeVariant, Ident, SimpleTypeVariant, Type, TypeDescriptor, Types}; #[derive(Debug)] pub(crate) struct TypedefMap(HashMap); @@ -10,10 +10,18 @@ impl TypedefMap { let mut ret = HashMap::new(); for (ident, type_) in &types.types { - if let TypeVariant::Reference(x) = &type_.variant { - if x.is_single() { + match type_ { + Type::SimpleType(TypeDescriptor { + variant: SimpleTypeVariant::Reference(x), + .. + }) + | Type::ComplexType(TypeDescriptor { + variant: ComplexTypeVariant::Reference(x), + .. + }) if x.is_single() => { ret.insert(ident.clone(), x.type_.clone()); } + _ => {} } } diff --git a/src/optimizer/remove_duplicates.rs b/src/optimizer/remove_duplicates.rs index 3864a8c7..d79fbc6e 100644 --- a/src/optimizer/remove_duplicates.rs +++ b/src/optimizer/remove_duplicates.rs @@ -1,7 +1,9 @@ use std::collections::HashMap; use std::hash::{Hash, Hasher}; -use crate::types::{ReferenceInfo, Type, TypeEq, TypeVariant, Types}; +use crate::types::{ + ComplexTypeVariant, ReferenceInfo, SimpleTypeVariant, Type, TypeDescriptor, TypeEq, Types, +}; use super::{Error, TypeTransformer}; @@ -86,7 +88,7 @@ impl TypeTransformer for RemoveDuplicates { } Entry::Occupied(e) => { let reference_ident = e.get(); - if !matches!(&type_.variant, TypeVariant::Reference(ti) if &ti.type_ == reference_ident) + if !matches!(&type_, Type::SimpleType(TypeDescriptor {variant: SimpleTypeVariant::Reference(ti), .. }) | Type::ComplexType(TypeDescriptor {variant: ComplexTypeVariant::Reference(ti), .. }) if &ti.type_ == reference_ident) { idents.insert(ident.clone(), reference_ident.clone()); } @@ -104,7 +106,16 @@ impl TypeTransformer for RemoveDuplicates { ); let ty = types.get_mut(&ident).unwrap(); - ty.variant = TypeVariant::Reference(ReferenceInfo::new(referenced_type)); + match ty { + Type::SimpleType(ty) => { + ty.variant = + SimpleTypeVariant::Reference(ReferenceInfo::new(referenced_type)); + } + Type::ComplexType(ty) => { + ty.variant = + ComplexTypeVariant::Reference(ReferenceInfo::new(referenced_type)); + } + } } } diff --git a/src/optimizer/resolve_typedefs.rs b/src/optimizer/resolve_typedefs.rs index ab3aa33f..1cf98c43 100644 --- a/src/optimizer/resolve_typedefs.rs +++ b/src/optimizer/resolve_typedefs.rs @@ -1,6 +1,6 @@ use std::collections::HashMap; -use crate::types::{Base, TypeVariant, Types}; +use crate::types::{Base, ComplexTypeVariant, SimpleTypeVariant, Types}; use super::{Error, TypeTransformer}; @@ -46,30 +46,23 @@ impl TypeTransformer for ResolveTypedefs { let mut replaced_references = HashMap::new(); - for type_ in types.values_mut() { - match &mut type_.variant { - TypeVariant::Reference(x) if x.is_single() => { + for (_, variant) in types.simple_types_iter_mut() { + match variant { + SimpleTypeVariant::Reference(x) if x.is_single() => { let new_type = typedefs.resolve(&x.type_).clone(); replaced_references .entry(x.type_.clone()) .or_insert_with(|| new_type.clone()); x.type_ = new_type; } - TypeVariant::Union(x) => { + SimpleTypeVariant::Union(x) => { resolve_base!(&mut x.base); for x in &mut *x.types { x.type_ = typedefs.resolve(&x.type_).clone(); } } - TypeVariant::Dynamic(x) => { - x.type_ = x.type_.as_ref().map(|x| typedefs.resolve(x)).cloned(); - - for x in &mut x.derived_types { - *x = typedefs.resolve(x).clone(); - } - } - TypeVariant::Enumeration(x) => { + SimpleTypeVariant::Enumeration(x) => { resolve_base!(&mut x.base); for x in &mut *x.variants { @@ -78,7 +71,27 @@ impl TypeTransformer for ResolveTypedefs { } } } - TypeVariant::ComplexType(x) => { + _ => (), + } + } + + for (_, variant) in types.complex_types_iter_mut() { + match variant { + ComplexTypeVariant::Reference(x) if x.is_single() => { + let new_type = typedefs.resolve(&x.type_).clone(); + replaced_references + .entry(x.type_.clone()) + .or_insert_with(|| new_type.clone()); + x.type_ = new_type; + } + ComplexTypeVariant::Dynamic(x) => { + x.type_ = x.type_.as_ref().map(|x| typedefs.resolve(x)).cloned(); + + for x in &mut x.derived_types { + *x = typedefs.resolve(x).clone(); + } + } + ComplexTypeVariant::ComplexType(x) => { resolve_base!(&mut x.base); if let Some(ident) = &mut x.content { @@ -89,7 +102,9 @@ impl TypeTransformer for ResolveTypedefs { attrib.type_ = typedefs.resolve(&attrib.type_).clone(); } } - TypeVariant::All(x) | TypeVariant::Choice(x) | TypeVariant::Sequence(x) => { + ComplexTypeVariant::All(x) + | ComplexTypeVariant::Choice(x) + | ComplexTypeVariant::Sequence(x) => { for element in &mut *x.elements { element.type_ = typedefs.resolve(&element.type_).clone(); } @@ -98,8 +113,8 @@ impl TypeTransformer for ResolveTypedefs { } } - for type_ in types.values_mut() { - let TypeVariant::Dynamic(di) = &mut type_.variant else { + for (_, variant) in types.complex_types_iter_mut() { + let ComplexTypeVariant::Dynamic(di) = variant else { continue; }; diff --git a/src/optimizer/unrestricted_base.rs b/src/optimizer/unrestricted_base.rs index 4970e5fc..822aaea9 100644 --- a/src/optimizer/unrestricted_base.rs +++ b/src/optimizer/unrestricted_base.rs @@ -1,4 +1,4 @@ -use crate::types::{ReferenceInfo, TypeVariant, Types}; +use crate::types::{ComplexTypeVariant, ReferenceInfo, SimpleTypeVariant, Types}; use super::{Error, TypeTransformer}; @@ -38,17 +38,21 @@ impl TypeTransformer for UseUnrestrictedBaseType { let bases = crate::optimizer::BaseMap::new(types); - for (ident, type_) in types.iter_mut() { - match &type_.variant { - TypeVariant::ComplexType(_) - | TypeVariant::Enumeration(_) - | TypeVariant::Union(_) => { - let base = bases.get_unrestricted(ident).clone(); - if *ident != base { - type_.variant = TypeVariant::Reference(ReferenceInfo::new(base)); - } + for (ident, variant) in types.complex_types_iter_mut() { + if let ComplexTypeVariant::ComplexType(_) = variant { + let base = bases.get_unrestricted(ident).clone(); + if *ident != base { + *variant = ComplexTypeVariant::Reference(ReferenceInfo::new(base)); + } + } + } + + for (ident, variant) in types.simple_types_iter_mut() { + if let SimpleTypeVariant::Enumeration(_) | SimpleTypeVariant::Union(_) = variant { + let base = bases.get_unrestricted(ident).clone(); + if *ident != base { + *variant = SimpleTypeVariant::Reference(ReferenceInfo::new(base)); } - _ => (), } } diff --git a/src/types/info/complex.rs b/src/types/info/complex.rs index 4e85992a..df0a8792 100644 --- a/src/types/info/complex.rs +++ b/src/types/info/complex.rs @@ -7,7 +7,7 @@ use crate::schema::xs::{ QnameListType, }; use crate::schema::{MaxOccurs, MinOccurs}; -use crate::types::{Ident, TypeEq, TypeVariant, Types}; +use crate::types::{ComplexTypeVariant, Ident, TypeEq, Types}; use super::{AttributesInfo, Base, ElementsInfo}; @@ -104,49 +104,45 @@ impl TypeEq for GroupInfo { impl ComplexInfo { /// Returns `true` if the content of this complex type information - /// is a [`TypeVariant::Choice`], `false` otherwise. + /// is a [`ComplexTypeVariant::Choice`], `false` otherwise. #[must_use] pub fn has_complex_choice_content(&self, types: &Types) -> bool { matches!( self.content .as_ref() - .and_then(|ident| types.get_resolved_type(ident)) + .and_then(|ident| types.get_resolved_complex_type(ident)) .map(|ty| &ty.variant), - Some(TypeVariant::Choice(_)) + Some(ComplexTypeVariant::Choice(_)) ) } /// Returns `true` if the content of this complex type information - /// is a [`TypeVariant::All`], [`TypeVariant::Choice`] or [`TypeVariant::Sequence`], + /// is a [`ComplexTypeVariant::All`], [`ComplexTypeVariant::Choice`] or [`ComplexTypeVariant::Sequence`], /// `false` otherwise. #[must_use] pub fn has_complex_content(&self, types: &Types) -> bool { matches!( self.content .as_ref() - .and_then(|ident| types.get_resolved_type(ident)) + .and_then(|ident| types.get_resolved_complex_type(ident)) .map(|ty| &ty.variant), - Some(TypeVariant::All(_) | TypeVariant::Choice(_) | TypeVariant::Sequence(_)) + Some( + ComplexTypeVariant::All(_) + | ComplexTypeVariant::Choice(_) + | ComplexTypeVariant::Sequence(_) + ) ) } /// Returns `true` if the content of this complex type information - /// is a [`TypeVariant::BuildIn`], [`TypeVariant::Union`] or [`TypeVariant::Enumeration`], + /// is a [`ComplexTypeVariant::BuildIn`], [`ComplexTypeVariant::Union`] or [`ComplexTypeVariant::Enumeration`], /// `false` otherwise. #[must_use] pub fn has_simple_content(&self, types: &Types) -> bool { - matches!( - self.content - .as_ref() - .and_then(|ident| types.get_resolved_type(ident)) - .map(|ty| &ty.variant), - Some( - TypeVariant::Reference(_) - | TypeVariant::BuildIn(_) - | TypeVariant::Union(_) - | TypeVariant::Enumeration(_) - ) - ) + self.content + .as_ref() + .and_then(|ident| types.get_resolved_simple_type(ident)) + .is_some() } } diff --git a/src/types/mod.rs b/src/types/mod.rs index 30373760..8b8d645f 100644 --- a/src/types/mod.rs +++ b/src/types/mod.rs @@ -25,7 +25,10 @@ pub use self::info::{ }; pub use self::name::Name; pub use self::name_builder::{NameBuilder, NameFallback}; -pub use self::type_::{BuildInInfo, Type, TypeEq, TypeVariant}; +pub use self::type_::{ + BuildInInfo, ComplexType, ComplexTypeVariant, SimpleType, SimpleTypeVariant, Type, + TypeDescriptor, TypeEq, TypeVariant, +}; use crate::schema::{Namespace, NamespaceId}; @@ -56,6 +59,88 @@ pub struct Module { } impl Types { + /// Returns the simple type with the given identifier. + #[must_use] + pub fn get_simple_type(&self, ident: &Ident) -> Option<&TypeDescriptor> { + self.types.get(ident).and_then(|t| match t { + Type::SimpleType(type_descriptor) => Some(type_descriptor), + _ => None, + }) + } + + /// Returns the mutable simple type with the given identifier. + #[must_use] + pub fn get_simple_type_mut( + &mut self, + ident: &Ident, + ) -> Option<&mut TypeDescriptor> { + self.types.get_mut(ident).and_then(|t| match t { + Type::SimpleType(type_descriptor) => Some(type_descriptor), + _ => None, + }) + } + + /// Returns the complex type with the given identifier. + #[must_use] + pub fn get_complex_type(&self, ident: &Ident) -> Option<&TypeDescriptor> { + self.types.get(ident).and_then(|t| match t { + Type::ComplexType(type_descriptor) => Some(type_descriptor), + _ => None, + }) + } + + /// Returns the mutable complex type with the given identifier. + #[must_use] + pub fn get_complex_type_mut( + &mut self, + ident: &Ident, + ) -> Option<&mut TypeDescriptor> { + self.types.get_mut(ident).and_then(|t| match t { + Type::ComplexType(type_descriptor) => Some(type_descriptor), + _ => None, + }) + } + + /// Returns an iterator over all simple types. + pub fn simple_types_iter(&self) -> impl Iterator { + self.types.iter().filter_map(|(ident, t)| match t { + Type::SimpleType(type_descriptor) => Some((ident, &type_descriptor.variant)), + Type::ComplexType(TypeDescriptor { + variant: ComplexTypeVariant::SimpleType(simple_type), + .. + }) => Some((ident, simple_type)), + _ => None, + }) + } + + /// Returns an iterator over all mutable simple types. + pub fn simple_types_iter_mut( + &mut self, + ) -> impl Iterator { + self.types.iter_mut().filter_map(|(ident, t)| match t { + Type::SimpleType(type_descriptor) => Some((ident, &mut type_descriptor.variant)), + _ => None, + }) + } + + /// Returns an iterator over all complex types. + pub fn complex_types_iter(&self) -> impl Iterator { + self.types.iter().filter_map(|(ident, t)| match t { + Type::ComplexType(type_descriptor) => Some((ident, &type_descriptor.variant)), + _ => None, + }) + } + + /// Returns an iterator over all mutable complex types. + pub fn complex_types_iter_mut( + &mut self, + ) -> impl Iterator { + self.types.iter_mut().filter_map(|(ident, t)| match t { + Type::ComplexType(type_descriptor) => Some((ident, &mut type_descriptor.variant)), + _ => None, + }) + } + /// Create a new [`NameBuilder`] instance, that can be used to build type named. pub fn name_builder(&mut self) -> NameBuilder { NameBuilder::new(self.next_name_id.clone()) @@ -83,31 +168,41 @@ impl Types { self.get_resolved(ident).map(|(_ident, ty)| ty) } - /// Get the type ident of the passed `ident` with all single type references resolved. + /// Get the complex type of the passed `ident` with all single type references resolved. /// - /// Like [`get_resolved`](Self::get_resolved), but instead of returning the identifier and - /// the type it will return only the identifier of the resolved type. + /// Simple utility over [`get_resolved_type`](Self::get_resolved_type) to return only complex types. #[must_use] - pub fn get_resolved_ident<'a>(&'a self, ident: &'a Ident) -> Option<&'a Ident> { - self.get_resolved(ident).map(|(ident, _ty)| ident) + pub fn get_resolved_complex_type<'a>( + &'a self, + ident: &'a Ident, + ) -> Option<&'a TypeDescriptor> { + self.get_resolved_type(ident).and_then(|a| match a { + Type::ComplexType(type_descriptor) => Some(type_descriptor), + _ => None, + }) } - /// Return the [`TypeVariant`] of corresponding type for the passed identifier. + /// Get the simple type of the passed `ident` with all single type references resolved. /// - /// This is a shorthand for `self.get(ident).map(|ty| &type.variant)`. - #[inline] + /// Simple utility over [`get_resolved_type`](Self::get_resolved_type) to return only simple types. #[must_use] - pub fn get_variant(&self, ident: &Ident) -> Option<&TypeVariant> { - self.get(ident).map(|ty| &ty.variant) + pub fn get_resolved_simple_type<'a>( + &'a self, + ident: &'a Ident, + ) -> Option<&'a TypeDescriptor> { + self.get_resolved_type(ident).and_then(|a| match a { + Type::SimpleType(type_descriptor) => Some(type_descriptor), + _ => None, + }) } - /// Return the [`TypeVariant`] of corresponding type for the passed identifier. + /// Get the type ident of the passed `ident` with all single type references resolved. /// - /// This is a shorthand for `self.get_mut(ident).map(|ty| &type.variant)`. - #[inline] + /// Like [`get_resolved`](Self::get_resolved), but instead of returning the identifier and + /// the type it will return only the identifier of the resolved type. #[must_use] - pub fn get_variant_mut(&mut self, ident: &Ident) -> Option<&mut TypeVariant> { - self.get_mut(ident).map(|ty| &mut ty.variant) + pub fn get_resolved_ident<'a>(&'a self, ident: &'a Ident) -> Option<&'a Ident> { + self.get_resolved(ident).map(|(ident, _ty)| ident) } } @@ -145,8 +240,15 @@ fn get_resolved_impl<'a>( let ty = types.get(ident)?; - match &ty.variant { - TypeVariant::Reference(x) if x.is_single() => { + match ty { + Type::SimpleType(TypeDescriptor { + variant: SimpleTypeVariant::Reference(x), + .. + }) + | Type::ComplexType(TypeDescriptor { + variant: ComplexTypeVariant::Reference(x), + .. + }) if x.is_single() => { visited.push(ident); let ret = match get_resolved_impl(types, &x.type_, visited) { diff --git a/src/types/type_.rs b/src/types/type_.rs index 7d1c090f..459d571d 100644 --- a/src/types/type_.rs +++ b/src/types/type_.rs @@ -9,19 +9,143 @@ use super::{ UnionInfo, }; +/// The form of a simple type. +pub type SimpleType = TypeDescriptor; + +/// The form of a complex type. +pub type ComplexType = TypeDescriptor; + +/// Either a [`SimpleType`] or a [`ComplexType`]. +#[derive(Debug, Clone)] +#[allow(clippy::large_enum_variant)] +pub enum Type { + /// A simple type. + SimpleType(SimpleType), + /// A complex type. + ComplexType(ComplexType), +} + +impl Type { + /// Returns a reference to the display name of this type. + #[must_use] + pub fn display_name(&self) -> Option<&str> { + match self { + Type::SimpleType(TypeDescriptor { display_name, .. }) + | Type::ComplexType(TypeDescriptor { display_name, .. }) => display_name.as_deref(), + } + } + + /// Returns a mutable reference to the display name of this type. + pub fn display_name_mut(&mut self) -> &mut Option { + match self { + Type::SimpleType(TypeDescriptor { display_name, .. }) + | Type::ComplexType(TypeDescriptor { display_name, .. }) => display_name, + } + } + + /// Returns a reference to the variant of this type. + #[must_use] + pub fn variant(&self) -> TypeVariant<&SimpleTypeVariant, &ComplexTypeVariant> { + match self { + Type::SimpleType(type_descriptor) => TypeVariant::SimpleType(&type_descriptor.variant), + Type::ComplexType(type_descriptor) => { + TypeVariant::ComplexType(&type_descriptor.variant) + } + } + } + + /// Returns a mutable reference to the variant of this type. + pub fn variant_mut(&mut self) -> TypeVariant<&mut SimpleTypeVariant, &mut ComplexTypeVariant> { + match self { + Type::SimpleType(type_descriptor) => { + TypeVariant::SimpleType(&mut type_descriptor.variant) + } + Type::ComplexType(type_descriptor) => { + TypeVariant::ComplexType(&mut type_descriptor.variant) + } + } + } + + /// Returns the simple type if this type is a simple type. + #[must_use] + pub fn simple_type_ref(&self) -> Option<&SimpleType> { + match self { + Type::SimpleType(type_descriptor) => Some(type_descriptor), + _ => None, + } + } + + /// Returns the complex type if this type is a complex type. + #[must_use] + pub fn complex_type_ref(&self) -> Option<&ComplexType> { + match self { + Type::ComplexType(type_descriptor) => Some(type_descriptor), + _ => None, + } + } + + /// Returns the reference info if this type is a reference. + #[must_use] + pub fn reference_type(&self) -> Option<&ReferenceInfo> { + match self { + Type::SimpleType(TypeDescriptor { + variant: SimpleTypeVariant::Reference(ri), + .. + }) + | Type::ComplexType(TypeDescriptor { + variant: ComplexTypeVariant::Reference(ri), + .. + }) => Some(ri), + _ => None, + } + } +} + /// Represents a type that was read and interpreted from an XML schema. #[derive(Debug, Clone)] -pub struct Type { +pub struct TypeDescriptor { /// Name to use for rendering instead of the auto generated name. pub display_name: Option, /// Actual data type this type represents. - pub variant: TypeVariant, + pub variant: T, +} + +/// Represents either a simple or complex type variant, with generics for dereferenced variants. +#[derive(Debug, Clone)] +pub enum TypeVariant { + /// Represents a simple type variant. + SimpleType(S), + /// Represents a complex type variant. + ComplexType(C), +} + +impl TypeVariant { + /// Converts the variant into a [`ComplexTypeVariant`]. + #[must_use] + pub fn into_complex_type_variant(self) -> ComplexTypeVariant { + match self { + TypeVariant::SimpleType(variant) => ComplexTypeVariant::SimpleType(variant), + TypeVariant::ComplexType(variant) => variant, + } + } +} + +impl, C: Deref> + TypeVariant +{ + /// Clones the variant in a generic way. + pub fn cloned(&self) -> TypeVariant { + match self { + TypeVariant::SimpleType(variant) => TypeVariant::SimpleType((**variant).clone()), + TypeVariant::ComplexType(variant) => TypeVariant::ComplexType((**variant).clone()), + } + } } /// Actual data type a [`Type`] represents. #[derive(Debug, Clone)] -pub enum TypeVariant { +pub enum SimpleTypeVariant { /// Represents a union type Union(UnionInfo), @@ -33,6 +157,13 @@ pub enum TypeVariant { /// Represents an enumeration Enumeration(EnumerationInfo), +} + +/// Actual data type a [`Type`] represents. +#[derive(Debug, Clone)] +pub enum ComplexTypeVariant { + /// References an other type + Reference(ReferenceInfo), /// Represents an dynamic element Dynamic(DynamicInfo), @@ -48,6 +179,9 @@ pub enum TypeVariant { /// Represents a complex type ComplexType(ComplexInfo), + + /// Represents a simple type + SimpleType(SimpleTypeVariant), } /// Trait to check if two types are equal to each other or not. @@ -127,25 +261,62 @@ pub enum BuildInInfo { /* Type */ macro_rules! impl_from { - ($var:ident, $ty:ty) => { - impl From<$ty> for Type { + ($var:ident, $t:ty, $ty:ty) => { + impl ::std::convert::From<$ty> for TypeDescriptor<$t> { fn from(value: $ty) -> Self { - Type::new(TypeVariant::$var(value)) + TypeDescriptor::new(<$t>::$var(value)) } } }; } -impl_from!(Reference, ReferenceInfo); -impl_from!(BuildIn, BuildInInfo); -impl_from!(Enumeration, EnumerationInfo); -impl_from!(Dynamic, DynamicInfo); -impl_from!(ComplexType, ComplexInfo); +macro_rules! impl_from_simple_type { + ($var:ident, $t:ty, $ty:ty) => { + impl ::std::convert::From<$ty> for Type { + fn from(value: $ty) -> Self { + Type::SimpleType(TypeDescriptor::<$t>::from(value)) + } + } + }; +} -impl Type { +macro_rules! impl_from_complex_type { + ($var:ident, $t:ty, $ty:ty) => { + impl ::std::convert::From<$ty> for Type { + fn from(value: $ty) -> Self { + Type::ComplexType(TypeDescriptor::<$t>::from(value)) + } + } + }; +} + +impl_from!(Reference, SimpleTypeVariant, ReferenceInfo); +impl_from!(Reference, ComplexTypeVariant, ReferenceInfo); +impl_from!(BuildIn, SimpleTypeVariant, BuildInInfo); +impl_from!(Enumeration, SimpleTypeVariant, EnumerationInfo); +impl_from!(Dynamic, ComplexTypeVariant, DynamicInfo); +impl_from!(ComplexType, ComplexTypeVariant, ComplexInfo); +impl_from_simple_type!(BuildIn, SimpleTypeVariant, BuildInInfo); +impl_from_simple_type!(Enumeration, SimpleTypeVariant, EnumerationInfo); +impl_from_complex_type!(Dynamic, ComplexTypeVariant, DynamicInfo); +impl_from_complex_type!(ComplexType, ComplexTypeVariant, ComplexInfo); + +impl From for Type { + fn from(value: SimpleType) -> Self { + Type::SimpleType(value) + } +} + +impl From for Type { + fn from(value: ComplexType) -> Self { + Type::ComplexType(value) + } +} + +impl TypeDescriptor { /// Create a new [`Type`] instance from the passed `variant`. #[must_use] - pub fn new(variant: TypeVariant) -> Self { + pub fn new(variant: T) -> Self { Self { variant, display_name: None, @@ -153,24 +324,24 @@ impl Type { } } -impl Deref for Type { - type Target = TypeVariant; +impl Deref for TypeDescriptor { + type Target = T; fn deref(&self) -> &Self::Target { &self.variant } } -impl DerefMut for Type { +impl DerefMut for TypeDescriptor { fn deref_mut(&mut self) -> &mut Self::Target { &mut self.variant } } -impl TypeEq for Type { +impl TypeEq for SimpleType { fn type_hash(&self, hasher: &mut H, types: &Types) { #[allow(clippy::enum_glob_use)] - use TypeVariant::*; + use SimpleTypeVariant::*; self.display_name.hash(hasher); @@ -179,27 +350,83 @@ impl TypeEq for Type { BuildIn(x) => x.hash(hasher), Reference(x) => x.type_hash(hasher, types), Enumeration(x) => x.type_hash(hasher, types), - Dynamic(x) => x.type_hash(hasher, types), - All(x) => x.type_hash(hasher, types), - Choice(x) => x.type_hash(hasher, types), - Sequence(x) => x.type_hash(hasher, types), - ComplexType(x) => x.type_hash(hasher, types), } } fn type_eq(&self, other: &Self, types: &Types) -> bool { - #[allow(clippy::enum_glob_use)] - use TypeVariant::*; - if self.display_name != other.display_name { return false; } - match (&self.variant, &other.variant) { + self.variant.type_eq(&other.variant, types) + } +} + +impl TypeEq for SimpleTypeVariant { + fn type_hash(&self, hasher: &mut H, types: &Types) { + #[allow(clippy::enum_glob_use)] + use SimpleTypeVariant::*; + + match &self { + Union(x) => x.type_hash(hasher, types), + BuildIn(x) => x.hash(hasher), + Reference(x) => x.type_hash(hasher, types), + Enumeration(x) => x.type_hash(hasher, types), + } + } + + fn type_eq(&self, other: &Self, types: &Types) -> bool { + #[allow(clippy::enum_glob_use)] + use SimpleTypeVariant::*; + + match (&self, &other) { (Union(x), Union(y)) => x.type_eq(y, types), (BuildIn(x), BuildIn(y)) => x == y, (Reference(x), Reference(y)) => x.type_eq(y, types), (Enumeration(x), Enumeration(y)) => x.type_eq(y, types), + (_, _) => false, + } + } +} + +impl TypeEq for ComplexType { + fn type_hash(&self, hasher: &mut H, types: &Types) { + self.display_name.hash(hasher); + + self.variant.type_hash(hasher, types); + } + + fn type_eq(&self, other: &Self, types: &Types) -> bool { + if self.display_name != other.display_name { + return false; + } + + self.variant.type_eq(&other.variant, types) + } +} + +impl TypeEq for ComplexTypeVariant { + fn type_hash(&self, hasher: &mut H, types: &Types) { + #[allow(clippy::enum_glob_use)] + use ComplexTypeVariant::*; + + match &self { + Reference(x) => x.type_hash(hasher, types), + Dynamic(x) => x.type_hash(hasher, types), + All(x) => x.type_hash(hasher, types), + Choice(x) => x.type_hash(hasher, types), + Sequence(x) => x.type_hash(hasher, types), + ComplexType(x) => x.type_hash(hasher, types), + SimpleType(x) => x.type_hash(hasher, types), + } + } + + fn type_eq(&self, other: &Self, types: &Types) -> bool { + #[allow(clippy::enum_glob_use)] + use ComplexTypeVariant::*; + + match (&self, &other) { + (Reference(x), Reference(y)) => x.type_eq(y, types), (Dynamic(x), Dynamic(y)) => x.type_eq(y, types), (All(x), All(y)) => x.type_eq(y, types), (Choice(x), Choice(y)) => x.type_eq(y, types), @@ -210,6 +437,23 @@ impl TypeEq for Type { } } +impl TypeEq for Type { + fn type_hash(&self, hasher: &mut H, types: &Types) { + match self { + Type::SimpleType(type_descriptor) => type_descriptor.type_hash(hasher, types), + Type::ComplexType(type_descriptor) => type_descriptor.type_hash(hasher, types), + } + } + + fn type_eq(&self, other: &Self, types: &Types) -> bool { + match (self, other) { + (Type::SimpleType(x), Type::SimpleType(y)) => x.type_eq(y, types), + (Type::ComplexType(x), Type::ComplexType(y)) => x.type_eq(y, types), + (_, _) => false, + } + } +} + /* BuildInInfo */ impl BuildInInfo { diff --git a/tests/feature/type_name_clash/mod.rs b/tests/feature/type_name_clash/mod.rs index d381e773..6b472dec 100644 --- a/tests/feature/type_name_clash/mod.rs +++ b/tests/feature/type_name_clash/mod.rs @@ -37,12 +37,12 @@ fn generate_default() { let ty1 = types .get_mut(&ident_1) .expect("Failed to resolve `tns:fooType`"); - ty1.display_name = Some("Bar".into()); + *ty1.display_name_mut() = Some("Bar".into()); let ty2 = types .get_mut(&ident_2) .expect("Failed to resolve `tns:FooType`"); - ty2.display_name = Some("Baz".into()); + *ty2.display_name_mut() = Some("Baz".into()); let code = exec_generator(config.generator, &schemas, &types).expect("Generator failed"); let code = code.to_string();