From 4dd8673fe3f543025d43abbf43e382f642bb6656 Mon Sep 17 00:00:00 2001 From: Lukas Friman Date: Thu, 24 Apr 2025 15:25:28 +0200 Subject: [PATCH 01/12] Initial restructure of interpreter. --- src/interpreter/builders/attribute_type.rs | 177 +++ src/interpreter/builders/complex_type.rs | 1030 +++++++++++++++++ src/interpreter/builders/element.rs | 293 +++++ src/interpreter/builders/mod.rs | 116 ++ src/interpreter/builders/simple_type.rs | 341 ++++++ .../variant_type_xample.rs} | 139 +-- src/interpreter/mod.rs | 3 +- src/interpreter/name_builder.rs | 2 +- src/interpreter/schema.rs | 80 +- src/interpreter/state.rs | 2 +- 10 files changed, 2031 insertions(+), 152 deletions(-) create mode 100644 src/interpreter/builders/attribute_type.rs create mode 100644 src/interpreter/builders/complex_type.rs create mode 100644 src/interpreter/builders/element.rs create mode 100644 src/interpreter/builders/mod.rs create mode 100644 src/interpreter/builders/simple_type.rs rename src/interpreter/{variant_builder.rs => builders/variant_type_xample.rs} (91%) diff --git a/src/interpreter/builders/attribute_type.rs b/src/interpreter/builders/attribute_type.rs new file mode 100644 index 00000000..fa80fd9a --- /dev/null +++ b/src/interpreter/builders/attribute_type.rs @@ -0,0 +1,177 @@ +use std::ops::{Deref, DerefMut}; + +use tracing::instrument; + +use super::Update; +use crate::schema::xs::AttributeType; +use crate::types::{ + AttributeInfo, Ident, IdentType, Name, ReferenceInfo, Type, TypeVariant, 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, + + /// `true` if `type_` is fixed and can not be changed anymore + fixed: bool, + + owner: &'a mut SchemaInterpreter<'schema, 'state>, +} + +/* any type */ + +/// Initialize the type of a `$builder` to any type `$variant`. +macro_rules! init_any { + ($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), + } + }; +} + +/* 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, + fixed: false, + owner, + } + } + + pub(crate) fn finish(self) -> Result { + println!("AttributeTypeBuilder::finish"); + self.type_ + .or_else(|| self.variant.map(Type::new)) + .ok_or(Error::NoType) + } + + #[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_)?; + init_any!(self, Reference, ReferenceInfo::new(type_), false); + } 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 = get_or_init_any!(self, ComplexType); + 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 = get_or_init_any!(self, ComplexType); + 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_extend2(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 = get_or_init_any!(self, ComplexType); + 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/builders/complex_type.rs b/src/interpreter/builders/complex_type.rs new file mode 100644 index 00000000..8ead12d8 --- /dev/null +++ b/src/interpreter/builders/complex_type.rs @@ -0,0 +1,1030 @@ +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, + RestrictionType, SimpleContent, Union, Use, +}; +use crate::schema::{MaxOccurs, MinOccurs}; +use crate::types::{ + AnyInfo, AttributeInfo, Base, ElementInfo, ElementMode, Ident, IdentType, Name, ReferenceInfo, + Type, TypeVariant, UnionTypeInfo, VariantInfo, VecHelper, +}; + +use super::super::{Error, SchemaInterpreter}; + +#[derive(Debug)] +pub(crate) struct ComplexTypeBuilder<'a, 'schema, 'state> { + type_: Option, + + /// Type variant that is constructed by the builder + 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, + + /// `true` if the simple content type of a complex type was already duplicated + /// and is now unique for this type. + is_simple_content_unique: bool, + + 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, + Simple, + Complex, +} + +#[derive(Debug, Clone, Copy, Eq, PartialEq)] +enum UpdateMode { + Extension, + Restriction, +} + +#[derive(Debug, Clone, Copy)] +enum ComplexContentType { + All, + Choice, + Sequence, +} + +/* any type */ + +/// Initialize the type of a `$builder` to any type `$variant`. +macro_rules! init_any { + ($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> 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(crate) fn finish(self) -> Result { + self.type_ + .or_else(|| self.variant.map(Type::new)) + .ok_or(Error::NoType) + } + + #[instrument(err, level = "trace", skip(self))] + 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); + + for c in &ty.content { + match c { + C::Annotation(_) | C::OpenContent(_) | C::Assert(_) => (), + C::ComplexContent(x) => { + let ci = get_or_init_any!(self, ComplexType); + ci.is_dynamic = ty.abstract_; + self.apply_complex_content(x)?; + } + C::SimpleContent(x) => self.apply_simple_content(x)?, + C::All(x) => self.apply_all(x)?, + C::Choice(x) => self.apply_choice(x)?, + C::Sequence(x) => self.apply_sequence(x)?, + C::Attribute(x) => self.apply_attribute_ref(x)?, + C::AnyAttribute(x) => self.apply_any_attribute(x)?, + C::Group(x) => self.apply_group_ref(x)?, + C::AttributeGroup(x) => self.apply_attribute_group_ref(x)?, + } + } + + Ok(()) + } + + #[instrument(err, level = "trace", skip(self))] + fn apply_simple_content(&mut self, ty: &SimpleContent) -> Result<(), Error> { + use crate::schema::xs::SimpleContentContent as C; + + self.content_mode = ContentMode::Simple; + + for c in &ty.content { + match c { + C::Annotation(_) => (), + C::Extension(x) => self.apply_simple_content_extension(x)?, + C::Restriction(x) => self.apply_simple_content_restriction(x)?, + } + } + + Ok(()) + } + + #[instrument(err, level = "trace", skip(self))] + fn apply_complex_content(&mut self, ty: &ComplexContent) -> Result<(), Error> { + use crate::schema::xs::ComplexContentContent as C; + + get_or_init_any!(self, ComplexType); + + for c in &ty.content { + match c { + C::Annotation(_) => (), + C::Extension(x) => self.apply_complex_content_extension(x)?, + C::Restriction(x) => self.apply_complex_content_restriction(x)?, + } + } + + Ok(()) + } + + #[instrument(err, level = "trace", skip(self))] + fn apply_simple_content_extension(&mut self, ty: &ExtensionType) -> Result<(), Error> { + let base = self.parse_qname(&ty.base)?; + + self.copy_base_type(&base, UpdateMode::Extension)?; + 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), + e => crate::unreachable!("Unexpected type: {e:#?}!"), + } + + Ok(()) + } + + #[instrument(err, level = "trace", skip(self))] + fn apply_simple_content_restriction(&mut self, ty: &RestrictionType) -> Result<(), Error> { + let base = self.parse_qname(&ty.base)?; + + self.copy_base_type(&base, UpdateMode::Restriction)?; + 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), + e => crate::unreachable!("Unexpected type: {e:#?}!"), + } + + Ok(()) + } + + #[instrument(err, level = "trace", skip(self))] + fn apply_complex_content_extension(&mut self, ty: &ExtensionType) -> Result<(), Error> { + let base = self.parse_qname(&ty.base)?; + + self.copy_base_type(&base, UpdateMode::Extension)?; + self.apply_extension(ty)?; + + let ci = get_or_init_any!(self, ComplexType); + ci.base = Base::Extension(base); + + Ok(()) + } + + #[instrument(err, level = "trace", skip(self))] + fn apply_complex_content_restriction(&mut self, ty: &RestrictionType) -> Result<(), Error> { + let base = self.parse_qname(&ty.base)?; + + self.copy_base_type(&base, UpdateMode::Restriction)?; + self.apply_restriction(ty)?; + + let ci = get_or_init_any!(self, ComplexType); + ci.base = Base::Restriction(base); + + Ok(()) + } + + #[instrument(err, level = "trace", skip(self))] + fn apply_extension(&mut self, ty: &ExtensionType) -> Result<(), Error> { + use crate::schema::xs::ExtensionTypeContent as C; + + for c in &ty.content { + match c { + C::Annotation(_) | C::OpenContent(_) | C::Assert(_) => (), + C::All(x) => self.apply_all(x)?, + C::AnyAttribute(x) => self.apply_any_attribute(x)?, + C::Attribute(x) => self.apply_attribute_ref(x)?, + C::AttributeGroup(x) => self.apply_attribute_group_ref(x)?, + C::Choice(x) => self.apply_choice(x)?, + C::Group(x) => self.apply_group_ref(x)?, + C::Sequence(x) => self.apply_sequence(x)?, + } + } + + Ok(()) + } + + #[instrument(err, level = "trace", skip(self))] + fn apply_restriction(&mut self, ty: &RestrictionType) -> Result<(), Error> { + use crate::schema::xs::RestrictionTypeContent as C; + + for c in &ty.content { + match c { + C::Annotation(_) | C::OpenContent(_) | C::Assert(_) => (), + C::All(x) => self.apply_all(x)?, + C::AnyAttribute(x) => self.apply_any_attribute(x)?, + C::Attribute(x) => self.apply_attribute_ref(x)?, + C::AttributeGroup(x) => self.apply_attribute_group_ref(x)?, + C::Choice(x) => self.apply_choice(x)?, + 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) => { + 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_all(&mut self, ty: &GroupType) -> Result<(), Error> { + let (field_name, type_ident) = self.make_field_name_and_type(ty); + + self.create_subtype_builder( + field_name, + ty.min_occurs, + ty.max_occurs, + type_ident, + ComplexContentType::All, + |builder| builder.apply_group(ty), + )?; + + Ok(()) + } + + #[instrument(err, level = "trace", skip(self))] + fn apply_choice(&mut self, ty: &GroupType) -> Result<(), Error> { + let (field_name, type_ident) = self.make_field_name_and_type(ty); + + self.create_subtype_builder( + field_name, + ty.min_occurs, + ty.max_occurs, + type_ident, + ComplexContentType::Choice, + |builder| builder.apply_group(ty), + )?; + + Ok(()) + } + + #[instrument(err, level = "trace", skip(self))] + fn apply_sequence(&mut self, ty: &GroupType) -> Result<(), Error> { + let (field_name, type_ident) = self.make_field_name_and_type(ty); + + self.create_subtype_builder( + field_name, + ty.min_occurs, + ty.max_occurs, + type_ident, + ComplexContentType::Sequence, + |builder| builder.apply_group(ty), + )?; + + Ok(()) + } + + #[instrument(err, level = "trace", skip(self))] + fn apply_group(&mut self, ty: &GroupType) -> Result<(), Error> { + use crate::schema::xs::GroupTypeContent as C; + + for c in &ty.content { + match c { + C::Annotation(_) => (), + C::All(x) => self.apply_all(x)?, + C::Choice(x) => self.apply_choice(x)?, + C::Sequence(x) => self.apply_sequence(x)?, + C::Any(x) => self.apply_any(x)?, + C::Group(x) => self.apply_group_ref(x)?, + C::Element(x) => self.apply_element_ref(x)?, + } + } + + Ok(()) + } + + #[instrument(err, level = "trace", skip(self))] + fn apply_element_ref(&mut self, ty: &ElementType) -> Result<(), Error> { + match ty { + ElementType { + ref_: Some(ref_), + name, + .. + } => { + let type_ = self.parse_qname(ref_)?.with_type(IdentType::Element); + let name = self.state.name_builder().or(name).or(&type_.name).finish(); + let ident = Ident::new(name) + .with_ns(type_.ns) + .with_type(IdentType::Element); + + let ci = get_or_init_type!(self, Sequence); + let element = ci.elements.find_or_insert(ident, |ident| { + ElementInfo::new(ident, type_, ElementMode::Element) + }); + crate::assert_eq!(element.element_mode, ElementMode::Element); + element.update(ty); + } + ty => { + let field_name = self.state.name_builder().or(&ty.name).finish(); + let field_ident = Ident::new(field_name) + .with_ns(self.state.current_ns()) + .with_type(IdentType::Element); + let type_name = self + .state + .name_builder() + .extend(true, ty.name.clone()) + .auto_extend2(true, false, self.state); + let type_name = if type_name.has_extension() { + type_name.with_id(false) + } else { + type_name.shared_name("Temp") + }; + let type_name = type_name.finish(); + + 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 element = ci.elements.find_or_insert(field_ident, |ident| { + ElementInfo::new(ident, type_, ElementMode::Element) + }); + crate::assert_eq!(element.element_mode, ElementMode::Element); + element.update(ty); + } + } + + Ok(()) + } + + #[instrument(err, level = "trace", skip(self))] + fn apply_group_ref(&mut self, ty: &GroupType) -> Result<(), Error> { + use crate::schema::xs::GroupTypeContent as C; + + let ref_ = ty.ref_.as_ref().ok_or(Error::GroupMissingRef)?; + let ref_ = self.parse_qname(ref_)?.with_type(IdentType::Group); + let group = self + .find_group(ref_.clone()) + .ok_or(Error::UnknownElement(ref_))?; + + self.state.type_stack.push(None); + + for c in &group.content { + match c { + C::Annotation(_) => (), + C::Any(x) => self.apply_any(x)?, + C::All(x) => self.apply_all(&x.patch(ty))?, + C::Choice(x) => self.apply_choice(&x.patch(ty))?, + C::Sequence(x) => self.apply_sequence(&x.patch(ty))?, + C::Group(x) => self.apply_group_ref(x)?, + C::Element(x) => self.apply_element_ref(x)?, + } + } + + self.state.type_stack.pop(); + + Ok(()) + } + + #[instrument(err, level = "trace", skip(self))] + fn apply_attribute_group_ref(&mut self, ty: &AttributeGroupType) -> Result<(), Error> { + use crate::schema::xs::AttributeGroupTypeContent as C; + + let ref_ = ty.ref_.as_ref().ok_or(Error::AttributeGroupMissingRef)?; + let ref_ = self.parse_qname(ref_)?.with_type(IdentType::AttributeGroup); + let group = self + .find_attribute_group(ref_.clone()) + .ok_or(Error::UnknownElement(ref_))?; + + self.state.type_stack.push(None); + + for c in &group.content { + match c { + C::Annotation(_) => (), + C::Attribute(x) => self.apply_attribute_ref(x)?, + C::AnyAttribute(x) => self.apply_any_attribute(x)?, + C::AttributeGroup(x) => self.apply_attribute_group_ref(x)?, + } + } + + self.state.type_stack.pop(); + + 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 = get_or_init_any!(self, ComplexType); + 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 = get_or_init_any!(self, ComplexType); + 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_extend2(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 = get_or_init_any!(self, ComplexType); + 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(()) + } + + #[instrument(err, level = "trace", skip(self))] + fn apply_any(&mut self, ty: &Any) -> Result<(), Error> { + let si = get_or_init_type!(self, Sequence); + si.any.create_or_update(ty); + + Ok(()) + } + + #[instrument(err, level = "trace", skip(self))] + fn apply_any_attribute(&mut self, ty: &AnyAttribute) -> Result<(), Error> { + let ci = get_or_init_any!(self, ComplexType); + ci.any_attribute.create_or_update(ty); + + Ok(()) + } + + #[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_extend2(false, true, builder.owner.state) + .finish(); + let type_ = builder.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_ { + 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(()) + } + + 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; + + 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()); + + ty + } + Err(Error::UnknownType(_)) => { + self.fixed = true; + + self.owner.get_complex_type_variant(base)? + } + Err(error) => Err(error)?, + } + } + (TypeMode::Complex, ContentMode::Complex) => { + self.owner.get_complex_type_variant(base)? + } + (_, _) => crate::unreachable!("Unset or invalid combination!"), + }; + + tracing::debug!("{base:#?}"); + + let mut base = base.clone(); + + match (self.content_mode, &mut base) { + (ContentMode::Simple, TypeVariant::Enumeration(ei)) => ei.variants.clear(), + (ContentMode::Complex, TypeVariant::ComplexType(ci)) => { + if let Some(content_ident) = &ci.content { + let mut content_type = self + .owner + .state + .types + .get(content_ident) + .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) => { + si.elements.retain(|element| element.min_occurs > 0); + + if matches!( + si.any, + Some(AnyInfo { + min_occurs: Some(0), + .. + }) + ) { + si.any = None; + } + } + (_, UpdateMode::Extension) => (), + (_, _) => tracing::warn!("Complex type does not has `All`, `Choice` or `Sequence` as content: {content_ident:#?} => {content_type:#?}!"), + } + + let content_name = self.state.make_content_name(); + let content_ident = Ident::new(content_name).with_ns(self.state.current_ns()); + + self.state + .add_type(content_ident.clone(), content_type, false)?; + + ci.content = Some(content_ident); + } + } + (_, _) => (), + } + + 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); + ci.content.get_or_insert(base_ident); + } + (None, TypeMode::Complex, ContentMode::Simple | ContentMode::Complex) => { + self.variant = Some(base); + } + (_, _, _) => crate::unreachable!("Unset or invalid combination!"), + } + + tracing::debug!("{:#?}", self.variant); + + 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 ComplexTypeBuilder<'x, 'y, 'z>, + groups: &ElementSubstitutionGroupType, + f: &mut F, + ) -> Result<(), Error> + where + F: FnMut(&mut ComplexTypeBuilder<'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 ComplexTypeBuilder<'_, '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 + ); + }; + + let content = self.owner.get_simple_type_variant(&content_ident)?.clone(); + if !self.is_simple_content_unique { + self.is_simple_content_unique = true; + let content_name = self.owner.state.make_content_name(); + content_ident = Ident::new(content_name).with_ns(self.owner.state.current_ns()); + + ci.content = Some(content_ident.clone()); + } + + let mut builder = ComplexTypeBuilder::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); + + match self.owner.state.types.entry(content_ident) { + Entry::Vacant(e) => { + e.insert(content); + } + Entry::Occupied(e) => { + *e.into_mut() = content; + } + } + } + (TypeMode::Complex, ContentMode::Complex) => { + crate::unreachable!("Complex type with complex content tried to access simple content builder: {:?}", &self.variant); + } + (_, _) => crate::unreachable!("Unset or invalid combination!"), + } + + Ok(()) + } + + #[instrument(err, level = "trace", skip(self, f))] + fn create_subtype_builder( + &mut self, + field_name: Name, + min_occurs: MinOccurs, + max_occurs: MaxOccurs, + type_ident: Ident, + complex_content_type: ComplexContentType, + f: F, + ) -> Result<(), Error> + where + F: FnOnce(&mut ComplexTypeBuilder<'_, 'schema, 'state>) -> Result<(), Error>, + { + enum UpdateContentMode { + Unknown, + Update, + Append, + } + + let mut variant = None; + let mut update_content_mode = UpdateContentMode::Unknown; + + if let Some(TypeVariant::ComplexType(ci)) = &self.variant { + if let Some(content_ident) = &ci.content { + let content_ty = self + .owner + .state + .types + .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()); + update_content_mode = UpdateContentMode::Update; + } + (_, _) => update_content_mode = UpdateContentMode::Append, + } + } + } + + 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()), + }); + + let mut builder = ComplexTypeBuilder::new(&mut *self.owner); + builder.type_mode = self.type_mode; + builder.variant = Some(variant); + + f(&mut builder)?; + + let ty = builder.finish()?; + + let (TypeVariant::All(si) | TypeVariant::Choice(si) | TypeVariant::Sequence(si)) = + &ty.variant + else { + return Err(Error::ExpectedGroupType); + }; + + if si.elements.is_empty() && si.any.is_none() { + return Ok(()); + } + + let ns = self.state.current_ns(); + + match &mut self.variant { + Some(TypeVariant::ComplexType(ci)) => match update_content_mode { + UpdateContentMode::Unknown => { + self.owner.state.add_type(type_ident.clone(), ty, false)?; + + ci.content = Some(type_ident); + ci.min_occurs = ci.min_occurs.min(min_occurs); + ci.max_occurs = ci.max_occurs.max(max_occurs); + } + UpdateContentMode::Update => { + let content_ident = ci.content.as_ref().unwrap(); + + self.owner.state.types.insert(content_ident.clone(), ty); + + ci.min_occurs = ci.min_occurs.min(min_occurs); + ci.max_occurs = ci.max_occurs.max(max_occurs); + } + UpdateContentMode::Append => { + self.owner.state.add_type(type_ident.clone(), ty, false)?; + + 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 (TypeVariant::All(si) + | TypeVariant::Choice(si) + | TypeVariant::Sequence(si)) = content_variant + else { + unreachable!(); + }; + + let ident = Ident::new(field_name) + .with_ns(ns) + .with_type(IdentType::Group); + let element = si.elements.find_or_insert(ident, |ident| { + ElementInfo::new(ident, type_ident, ElementMode::Group) + }); + + element.min_occurs = element.min_occurs.min(min_occurs); + element.max_occurs = element.max_occurs.max(max_occurs); + } + }, + Some(TypeVariant::All(si) | TypeVariant::Choice(si) | TypeVariant::Sequence(si)) => { + self.owner.state.add_type(type_ident.clone(), ty, false)?; + + let ident = Ident::new(field_name) + .with_ns(ns) + .with_type(IdentType::Group); + let element = si.elements.find_or_insert(ident, |ident| { + ElementInfo::new(ident, type_ident, ElementMode::Group) + }); + + element.min_occurs = element.min_occurs.min(min_occurs); + element.max_occurs = element.max_occurs.max(max_occurs); + } + None => { + self.owner.state.add_type(type_ident.clone(), ty, false)?; + + let ci = get_or_init_any!(self, ComplexType); + + ci.content = Some(type_ident); + ci.min_occurs = ci.min_occurs.min(min_occurs); + ci.max_occurs = ci.max_occurs.max(max_occurs); + } + e => crate::unreachable!("{:?}", e), + } + + Ok(()) + } + + fn make_field_name_and_type(&mut self, ty: &GroupType) -> (Name, Ident) { + let name = self + .state + .name_builder() + .generate_id() + .or(ty.name.clone()) + .remove_suffix("Type") + .remove_suffix("Content"); + let field_name = name.clone().shared_name("Content").finish(); + let type_name = name + .auto_extend2(false, true, self.state) + .remove_suffix("Type") + .remove_suffix("Content") + .shared_name("Content") + .with_id(true) + .finish(); + let type_ = Ident::new(type_name).with_ns(self.state.current_ns()); + + (field_name, type_) + } +} + +impl<'schema, 'state> Deref for ComplexTypeBuilder<'_, 'schema, 'state> { + type Target = SchemaInterpreter<'schema, 'state>; + + fn deref(&self) -> &Self::Target { + self.owner + } +} + +impl DerefMut for ComplexTypeBuilder<'_, '_, '_> { + fn deref_mut(&mut self) -> &mut Self::Target { + self.owner + } +} diff --git a/src/interpreter/builders/element.rs b/src/interpreter/builders/element.rs new file mode 100644 index 00000000..d5d229e6 --- /dev/null +++ b/src/interpreter/builders/element.rs @@ -0,0 +1,293 @@ +use std::ops::{Deref, DerefMut}; + +use tracing::instrument; + +use super::Update; +use crate::schema::xs::{ElementSubstitutionGroupType, ElementType, GroupType}; +use crate::schema::Namespace; +use crate::types::{ + DynamicInfo, ElementInfo, ElementMode, Ident, IdentType, Name, ReferenceInfo, Type, + TypeVariant, VecHelper, +}; + +use super::super::{Error, SchemaInterpreter}; + +#[derive(Debug)] +pub(crate) struct ElementBuilder<'a, 'schema, 'state> { + /// Type variant that is constructed by the builder + variant: Option, + + /// `true` if `type_` is fixed and can not be changed anymore + fixed: bool, + + owner: &'a mut SchemaInterpreter<'schema, 'state>, +} + +/* 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 `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> ElementBuilder<'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 { + println!("ElementBuilder::finish"); + let variant = self.variant.ok_or(Error::NoType)?; + + Ok(Type::new(variant)) + } + + #[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_)?; + + 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 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_ { + 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))] + fn apply_element_ref(&mut self, ty: &ElementType) -> Result<(), Error> { + match ty { + ElementType { + ref_: Some(ref_), + name, + .. + } => { + let type_ = self.parse_qname(ref_)?.with_type(IdentType::Element); + let name = self.state.name_builder().or(name).or(&type_.name).finish(); + let ident = Ident::new(name) + .with_ns(type_.ns) + .with_type(IdentType::Element); + + let ci = get_or_init_type!(self, Sequence); + let element = ci.elements.find_or_insert(ident, |ident| { + ElementInfo::new(ident, type_, ElementMode::Element) + }); + crate::assert_eq!(element.element_mode, ElementMode::Element); + element.update(ty); + } + ty => { + let field_name = self.state.name_builder().or(&ty.name).finish(); + let field_ident = Ident::new(field_name) + .with_ns(self.state.current_ns()) + .with_type(IdentType::Element); + let type_name = self + .state + .name_builder() + .extend(true, ty.name.clone()) + .auto_extend2(true, false, self.state); + let type_name = if type_name.has_extension() { + type_name.with_id(false) + } else { + type_name.shared_name("Temp") + }; + let type_name = type_name.finish(); + + 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 element = ci.elements.find_or_insert(field_ident, |ident| { + ElementInfo::new(ident, type_, ElementMode::Element) + }); + crate::assert_eq!(element.element_mode, ElementMode::Element); + element.update(ty); + } + } + + 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) + } + + fn make_field_name_and_type(&mut self, ty: &GroupType) -> (Name, Ident) { + let name = self + .state + .name_builder() + .generate_id() + .or(ty.name.clone()) + .remove_suffix("Type") + .remove_suffix("Content"); + let field_name = name.clone().shared_name("Content").finish(); + let type_name = name + .auto_extend2(false, true, self.state) + .remove_suffix("Type") + .remove_suffix("Content") + .shared_name("Content") + .with_id(true) + .finish(); + let type_ = Ident::new(type_name).with_ns(self.state.current_ns()); + + (field_name, type_) + } +} + +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..43684e00 --- /dev/null +++ b/src/interpreter/builders/simple_type.rs @@ -0,0 +1,341 @@ +use std::ops::{Deref, DerefMut}; +use std::str::from_utf8; + +use tracing::instrument; + +use crate::schema::xs::{ + ExtensionType, Facet, FacetType, GroupType, List, Restriction, RestrictionType, SimpleBaseType, + Union, Use, +}; +use crate::schema::MaxOccurs; +use crate::types::{ + Base, Ident, IdentType, Name, ReferenceInfo, Type, TypeVariant, 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 + variant: Option, + + /// `true` if `type_` is fixed and can not be changed anymore + fixed: bool, + + owner: &'a mut SchemaInterpreter<'schema, 'state>, +} + +/* any type */ + +#[derive(Debug, Clone, Copy, Eq, PartialEq)] +#[allow(dead_code)] +enum UpdateMode { + Extension, + Restriction, +} + +/// Initialize the type of a `$builder` to any type `$variant`. +macro_rules! init_any { + ($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), + } + }; +} + +/* 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 { + let variant = self.variant.ok_or(Error::NoType)?; + + Ok(Type::new(variant)) + } + + #[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, 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:#?}"), + } + } + + Ok(()) + } + + #[instrument(err, level = "trace", skip(self))] + fn apply_extension(&mut self, ty: &ExtensionType) -> Result<(), Error> { + use crate::schema::xs::ExtensionTypeContent as C; + + for c in &ty.content { + match c { + C::Annotation(_) | C::OpenContent(_) | C::Assert(_) => (), + C::All(_) + | C::AnyAttribute(_) + | C::Attribute(_) + | C::AttributeGroup(_) + | C::Choice(_) + | C::Group(_) + | C::Sequence(_) => unreachable!(), + } + } + + Ok(()) + } + + #[instrument(err, level = "trace", skip(self))] + fn apply_restriction(&mut self, ty: &RestrictionType) -> Result<(), Error> { + use crate::schema::xs::RestrictionTypeContent as C; + + for c in &ty.content { + match c { + C::Annotation(_) | C::OpenContent(_) | C::Assert(_) => (), + C::SimpleType(x) => self.apply_simple_type(x)?, + C::Facet(x) => self.apply_facet(x)?, + C::AnyAttribute(_) + | C::All(_) + | C::Attribute(_) + | C::AttributeGroup(_) + | C::Choice(_) + | C::Group(_) + | C::Sequence(_) => unreachable!(), + } + } + + Ok(()) + } + #[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_type_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_type_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_extend2(false, true, builder.owner.state) + .finish(); + let type_ = builder.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_ { + self.simple_type_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(()) + } + + fn copy_base_type(&mut self, base: &Ident, _mode: UpdateMode) -> Result<(), Error> { + let base = { + self.fixed = false; + + self.owner.get_simple_type_variant(base)? + }; + + tracing::debug!("{base:#?}"); + + let mut base = base.clone(); + + if let TypeVariant::Enumeration(ei) = &mut base { + ei.variants.clear() + } + + self.variant = Some(base); + + tracing::debug!("{:#?}", self.variant); + + Ok(()) + } + + fn simple_type_builder(&mut self, f: F) -> Result<(), Error> + where + F: FnOnce(&mut SimpleTypeBuilder<'_, 'schema, 'state>) -> Result<(), Error>, + { + f(self)?; + + Ok(()) + } + + fn make_field_name_and_type(&mut self, ty: &GroupType) -> (Name, Ident) { + let name = self + .state + .name_builder() + .generate_id() + .or(ty.name.clone()) + .remove_suffix("Type") + .remove_suffix("Content"); + let field_name = name.clone().shared_name("Content").finish(); + let type_name = name + .auto_extend2(false, true, self.state) + .remove_suffix("Type") + .remove_suffix("Content") + .shared_name("Content") + .with_id(true) + .finish(); + let type_ = Ident::new(type_name).with_ns(self.state.current_ns()); + + (field_name, type_) + } +} + +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/variant_builder.rs b/src/interpreter/builders/variant_type_xample.rs similarity index 91% rename from src/interpreter/variant_builder.rs rename to src/interpreter/builders/variant_type_xample.rs index 01956d95..10b028c6 100644 --- a/src/interpreter/variant_builder.rs +++ b/src/interpreter/builders/variant_type_xample.rs @@ -16,10 +16,10 @@ use crate::types::{ IdentType, Name, ReferenceInfo, Type, TypeVariant, UnionTypeInfo, VariantInfo, 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 variant that is constructed by the builder variant: Option, @@ -117,8 +117,8 @@ macro_rules! get_or_init_type { /* 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 fn new(owner: &'a mut SchemaInterpreter<'schema, 'state>) -> Self { Self { variant: None, fixed: false, @@ -129,14 +129,14 @@ impl<'a, 'schema, 'state> VariantBuilder<'a, 'schema, 'state> { } } - pub(super) fn finish(self) -> Result { + pub fn finish(self) -> Result { let variant = self.variant.ok_or(Error::NoType)?; Ok(Type::new(variant)) } #[instrument(err, level = "trace", skip(self))] - pub(super) fn apply_element(&mut self, ty: &ElementType) -> Result<(), Error> { + pub fn apply_element(&mut self, ty: &ElementType) -> Result<(), Error> { use crate::schema::xs::ElementTypeContent as C; if let Some(type_) = &ty.type_ { @@ -557,7 +557,7 @@ impl<'a, 'schema, 'state> VariantBuilder<'a, 'schema, 'state> { .state .name_builder() .extend(true, ty.name.clone()) - .auto_extend(true, false, self.state); + .auto_extend2(true, false, self.state); let type_name = if type_name.has_extension() { type_name.with_id(false) } else { @@ -682,7 +682,7 @@ impl<'a, 'schema, 'state> VariantBuilder<'a, 'schema, 'state> { .state .name_builder() .or(name) - .auto_extend(true, true, self.state) + .auto_extend2(true, true, self.state) .finish(); let ns = self.state.current_ns(); @@ -769,7 +769,7 @@ impl<'a, 'schema, 'state> VariantBuilder<'a, 'schema, 'state> { .state .name_builder() .or(&x.name) - .auto_extend(false, true, builder.owner.state) + .auto_extend2(false, true, builder.owner.state) .finish(); let type_ = builder.owner.create_simple_type(ns, Some(name), x)?; ui.types.push(UnionTypeInfo::new(type_)); @@ -926,12 +926,12 @@ impl<'a, 'schema, 'state> VariantBuilder<'a, 'schema, 'state> { F: FnMut(&mut Self, &Ident) -> Result<(), Error>, { fn inner<'x, 'y, 'z, F>( - builder: &mut VariantBuilder<'x, 'y, 'z>, + builder: &mut ComplexTypeBuilder<'x, 'y, 'z>, groups: &ElementSubstitutionGroupType, f: &mut F, ) -> Result<(), Error> where - F: FnMut(&mut VariantBuilder<'x, 'y, 'z>, &Ident) -> Result<(), Error>, + F: FnMut(&mut ComplexTypeBuilder<'x, 'y, 'z>, &Ident) -> Result<(), Error>, { for head in &groups.0 { let ident = builder.parse_qname(head)?.with_type(IdentType::Element); @@ -954,7 +954,7 @@ impl<'a, 'schema, 'state> VariantBuilder<'a, 'schema, 'state> { fn simple_content_builder(&mut self, f: F) -> Result<(), Error> where - F: FnOnce(&mut VariantBuilder<'_, 'schema, 'state>) -> Result<(), Error>, + F: FnOnce(&mut ComplexTypeBuilder<'_, 'schema, 'state>) -> Result<(), Error>, { match (self.type_mode, self.content_mode) { (TypeMode::Simple, _) => f(self)?, @@ -977,7 +977,7 @@ impl<'a, 'schema, 'state> VariantBuilder<'a, 'schema, 'state> { ci.content = Some(content_ident.clone()); } - let mut builder = VariantBuilder::new(&mut *self.owner); + let mut builder = ComplexTypeBuilder::new(&mut *self.owner); builder.variant = Some(content); builder.type_mode = TypeMode::Simple; builder.content_mode = ContentMode::Simple; @@ -1016,7 +1016,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, @@ -1054,7 +1054,7 @@ impl<'a, 'schema, 'state> VariantBuilder<'a, 'schema, 'state> { ComplexContentType::Sequence => TypeVariant::Sequence(Default::default()), }); - let mut builder = VariantBuilder::new(&mut *self.owner); + let mut builder = ComplexTypeBuilder::new(&mut *self.owner); builder.type_mode = self.type_mode; builder.variant = Some(variant); @@ -1154,7 +1154,7 @@ impl<'a, 'schema, 'state> VariantBuilder<'a, 'schema, 'state> { .remove_suffix("Content"); let field_name = name.clone().shared_name("Content").finish(); let type_name = name - .auto_extend(false, true, self.state) + .auto_extend2(false, true, self.state) .remove_suffix("Type") .remove_suffix("Content") .shared_name("Content") @@ -1166,7 +1166,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 +1174,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/mod.rs b/src/interpreter/mod.rs index 0f3f57d0..d4926a08 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; @@ -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. /// diff --git a/src/interpreter/name_builder.rs b/src/interpreter/name_builder.rs index b6326c7a..9c3cb845 100644 --- a/src/interpreter/name_builder.rs +++ b/src/interpreter/name_builder.rs @@ -3,7 +3,7 @@ use crate::types::NameBuilder; use super::state::State; impl NameBuilder { - pub(super) fn auto_extend( + pub(super) fn auto_extend2( self, stop_at_group: bool, replace: bool, diff --git a/src/interpreter/schema.rs b/src/interpreter/schema.rs index 9c7161a5..cdf7d3e1 100644 --- a/src/interpreter/schema.rs +++ b/src/interpreter/schema.rs @@ -1,3 +1,4 @@ +use std::ops::DerefMut; use std::str::from_utf8; use tracing::instrument; @@ -10,19 +11,19 @@ use crate::schema::xs::{ use crate::schema::{Namespace, NamespaceId, QName, Schemas}; use crate::types::{Ident, IdentType, Name, Type, TypeVariant}; -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 +67,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 +83,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,12 +97,12 @@ 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<&TypeVariant, 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); } @@ -125,7 +126,7 @@ impl SchemaInterpreter<'_, '_> { } #[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> { @@ -133,7 +134,7 @@ impl SchemaInterpreter<'_, '_> { 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); } @@ -161,7 +162,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 +174,17 @@ impl SchemaInterpreter<'_, '_> { type_: IdentType::Element, }; - self.create_type(ident, |builder| builder.apply_element(ty)) + self.create_type_new(ident.clone(), move |mut owner| { + let mut builder = builders::ElementBuilder::new(owner.deref_mut()); + 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 +196,64 @@ impl SchemaInterpreter<'_, '_> { type_: IdentType::Attribute, }; - self.create_type(ident.clone(), |builder| builder.apply_attribute(ty)) + self.create_type_new(ident.clone(), move |mut owner| { + let mut builder = builders::AttributeTypeBuilder::new(owner.deref_mut()); + 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_new(ident.clone(), move |mut owner| { + let mut builder = builders::SimpleTypeBuilder::new(owner.deref_mut()); + 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_new(ident.clone(), move |mut owner| { + let mut builder = builders::ComplexTypeBuilder::new(owner.deref_mut()); + 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_new(&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 +267,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/interpreter/state.rs b/src/interpreter/state.rs index 2cff2ddc..90b9a667 100644 --- a/src/interpreter/state.rs +++ b/src/interpreter/state.rs @@ -52,7 +52,7 @@ impl<'a> State<'a> { pub(super) fn make_content_name(&mut self) -> Name { self.name_builder() - .auto_extend(false, true, self) + .auto_extend2(false, true, self) .remove_suffix("Type") .remove_suffix("Content") .shared_name("Content") From 86bf09ea230873cc7720c861ea657286d579a884 Mon Sep 17 00:00:00 2001 From: Lukas Friman Date: Fri, 25 Apr 2025 13:08:32 +0200 Subject: [PATCH 02/12] Removed duplicated logic for simple types in ComplexTypeBuilder. --- src/interpreter/builders/complex_type.rs | 76 ++++++++---------------- src/interpreter/builders/simple_type.rs | 6 +- 2 files changed, 27 insertions(+), 55 deletions(-) diff --git a/src/interpreter/builders/complex_type.rs b/src/interpreter/builders/complex_type.rs index 8ead12d8..16830606 100644 --- a/src/interpreter/builders/complex_type.rs +++ b/src/interpreter/builders/complex_type.rs @@ -29,9 +29,6 @@ pub(crate) struct ComplexTypeBuilder<'a, 'schema, 'state> { /// `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, @@ -42,13 +39,6 @@ pub(crate) struct ComplexTypeBuilder<'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, @@ -123,7 +113,6 @@ impl<'a, 'schema, 'state> ComplexTypeBuilder<'a, 'schema, 'state> { type_: None, variant: None, fixed: false, - type_mode: TypeMode::Unknown, content_mode: ContentMode::Unknown, is_simple_content_unique: false, owner, @@ -140,7 +129,6 @@ impl<'a, 'schema, 'state> ComplexTypeBuilder<'a, 'schema, 'state> { 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); @@ -672,35 +660,24 @@ impl<'a, 'schema, 'state> ComplexTypeBuilder<'a, 'schema, 'state> { 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; - - 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; + 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()); + simple_base_ident = Some(base.clone()); - ty - } - Err(Error::UnknownType(_)) => { - self.fixed = true; + ty + } + Err(Error::UnknownType(_)) => { + self.fixed = true; - self.owner.get_complex_type_variant(base)? - } - Err(error) => Err(error)?, + self.owner.get_complex_type_variant(base)? } - } - (TypeMode::Complex, ContentMode::Complex) => { - self.owner.get_complex_type_variant(base)? - } - (_, _) => crate::unreachable!("Unset or invalid combination!"), + Err(error) => Err(error)?, + }, + ContentMode::Complex => self.owner.get_complex_type_variant(base)?, + _ => crate::unreachable!("Unset or invalid combination!"), }; tracing::debug!("{base:#?}"); @@ -749,16 +726,15 @@ impl<'a, 'schema, 'state> ComplexTypeBuilder<'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) => { + match (simple_base_ident, self.content_mode) { + (Some(base_ident), ContentMode::Simple) => { let ci = get_or_init_any!(self, ComplexType); ci.content.get_or_insert(base_ident); } - (None, TypeMode::Complex, ContentMode::Simple | ContentMode::Complex) => { + (None, ContentMode::Simple | ContentMode::Complex) => { self.variant = Some(base); } - (_, _, _) => crate::unreachable!("Unset or invalid combination!"), + (_, _) => crate::unreachable!("Unset or invalid combination!"), } tracing::debug!("{:#?}", self.variant); @@ -803,11 +779,10 @@ impl<'a, 'schema, 'state> ComplexTypeBuilder<'a, 'schema, 'state> { fn simple_content_builder(&mut self, f: F) -> Result<(), Error> where - F: FnOnce(&mut ComplexTypeBuilder<'_, '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) => { + match self.content_mode { + ContentMode::Simple => { let ci = get_or_init_any!(self, ComplexType); let Some(mut content_ident) = ci.content.clone() else { @@ -826,10 +801,8 @@ impl<'a, 'schema, 'state> ComplexTypeBuilder<'a, 'schema, 'state> { ci.content = Some(content_ident.clone()); } - let mut builder = ComplexTypeBuilder::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)?; @@ -845,10 +818,10 @@ impl<'a, 'schema, 'state> ComplexTypeBuilder<'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(()) @@ -904,7 +877,6 @@ impl<'a, 'schema, 'state> ComplexTypeBuilder<'a, 'schema, 'state> { }); let mut builder = ComplexTypeBuilder::new(&mut *self.owner); - builder.type_mode = self.type_mode; builder.variant = Some(variant); f(&mut builder)?; diff --git a/src/interpreter/builders/simple_type.rs b/src/interpreter/builders/simple_type.rs index 43684e00..3fb031a7 100644 --- a/src/interpreter/builders/simple_type.rs +++ b/src/interpreter/builders/simple_type.rs @@ -18,12 +18,12 @@ use super::super::{Error, SchemaInterpreter}; #[derive(Debug)] pub(crate) struct SimpleTypeBuilder<'a, 'schema, 'state> { /// Type variant that is constructed by the builder - variant: Option, + pub variant: Option, /// `true` if `type_` is fixed and can not be changed anymore - fixed: bool, + pub fixed: bool, - owner: &'a mut SchemaInterpreter<'schema, 'state>, + pub owner: &'a mut SchemaInterpreter<'schema, 'state>, } /* any type */ From e94ca4f1fabda692e82967c2ddd56958ec482848 Mon Sep 17 00:00:00 2001 From: Lukas Friman Date: Fri, 25 Apr 2025 13:37:44 +0200 Subject: [PATCH 03/12] Removed unnecessary simple_type_builder function. --- src/interpreter/builders/simple_type.rs | 79 ++++++++++--------------- 1 file changed, 32 insertions(+), 47 deletions(-) diff --git a/src/interpreter/builders/simple_type.rs b/src/interpreter/builders/simple_type.rs index 3fb031a7..c9faa9ce 100644 --- a/src/interpreter/builders/simple_type.rs +++ b/src/interpreter/builders/simple_type.rs @@ -192,43 +192,39 @@ impl<'a, 'schema, 'state> SimpleTypeBuilder<'a, 'schema, 'state> { .with_ns(self.state.current_ns()) .with_type(IdentType::Enumeration); - self.simple_type_builder(|builder| { - let ei = get_or_init_any!(builder, Enumeration); - let var = ei.variants.find_or_insert(ident, VariantInfo::new); - var.use_ = Use::Required; + let ei = get_or_init_any!(self, Enumeration); + let var = ei.variants.find_or_insert(ident, VariantInfo::new); + var.use_ = Use::Required; - Ok(()) - }) + Ok(()) } #[instrument(err, level = "trace", skip(self))] fn apply_union(&mut self, ty: &Union) -> Result<(), Error> { - self.simple_type_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 ui = get_or_init_any!(self, Union); - let ns = builder.owner.state.current_ns(); - - for x in &ty.simple_type { - let name = builder - .owner - .state - .name_builder() - .or(&x.name) - .auto_extend2(false, true, builder.owner.state) - .finish(); - let type_ = builder.owner.create_simple_type(ns, Some(name), None, x)?; + 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_)); } + } - Ok(()) - }) + let ns = self.owner.state.current_ns(); + + for x in &ty.simple_type { + let name = self + .owner + .state + .name_builder() + .or(&x.name) + .auto_extend2(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))] @@ -260,17 +256,15 @@ impl<'a, 'schema, 'state> SimpleTypeBuilder<'a, 'schema, 'state> { } if let Some(type_) = type_ { - self.simple_type_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(()) - })?; - } + let ti = get_or_init_any!(self, Reference, ReferenceInfo::new(type_.clone())); + ti.type_ = type_; + ti.min_occurs = 0; + ti.max_occurs = MaxOccurs::Unbounded; - Ok(()) + Ok(()) + } else { + Ok(()) + } } fn copy_base_type(&mut self, base: &Ident, _mode: UpdateMode) -> Result<(), Error> { @@ -295,15 +289,6 @@ impl<'a, 'schema, 'state> SimpleTypeBuilder<'a, 'schema, 'state> { Ok(()) } - fn simple_type_builder(&mut self, f: F) -> Result<(), Error> - where - F: FnOnce(&mut SimpleTypeBuilder<'_, 'schema, 'state>) -> Result<(), Error>, - { - f(self)?; - - Ok(()) - } - fn make_field_name_and_type(&mut self, ty: &GroupType) -> (Name, Ident) { let name = self .state From 3664d6cbe4eed5b707e87ef0b498dacb46e82bfb Mon Sep 17 00:00:00 2001 From: Lukas Friman Date: Fri, 25 Apr 2025 14:19:38 +0200 Subject: [PATCH 04/12] Removed duplicate unused code and simplified simple type interactions in complex_type. --- src/interpreter/builders/complex_type.rs | 138 +- src/interpreter/builders/element.rs | 27 +- src/interpreter/builders/simple_type.rs | 73 +- .../builders/variant_type_xample.rs | 1181 ----------------- 4 files changed, 11 insertions(+), 1408 deletions(-) delete mode 100644 src/interpreter/builders/variant_type_xample.rs diff --git a/src/interpreter/builders/complex_type.rs b/src/interpreter/builders/complex_type.rs index 16830606..1ad40ed3 100644 --- a/src/interpreter/builders/complex_type.rs +++ b/src/interpreter/builders/complex_type.rs @@ -1,6 +1,5 @@ use std::collections::btree_map::Entry; use std::ops::{Deref, DerefMut}; -use std::str::from_utf8; use tracing::instrument; @@ -8,13 +7,12 @@ 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, - RestrictionType, SimpleContent, Union, Use, + ElementType, ExtensionType, Facet, GroupType, RestrictionType, SimpleContent, }; use crate::schema::{MaxOccurs, MinOccurs}; use crate::types::{ - AnyInfo, AttributeInfo, Base, ElementInfo, ElementMode, Ident, IdentType, Name, ReferenceInfo, - Type, TypeVariant, UnionTypeInfo, VariantInfo, VecHelper, + AnyInfo, AttributeInfo, Base, ElementInfo, ElementMode, Ident, IdentType, Name, Type, + TypeVariant, VecHelper, }; use super::super::{Error, SchemaInterpreter}; @@ -562,100 +560,7 @@ impl<'a, 'schema, 'state> ComplexTypeBuilder<'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_extend2(false, true, builder.owner.state) - .finish(); - let type_ = builder.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_ { - 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> { @@ -742,41 +647,6 @@ impl<'a, 'schema, 'state> ComplexTypeBuilder<'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 ComplexTypeBuilder<'x, 'y, 'z>, - groups: &ElementSubstitutionGroupType, - f: &mut F, - ) -> Result<(), Error> - where - F: FnMut(&mut ComplexTypeBuilder<'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 SimpleTypeBuilder<'_, 'schema, 'state>) -> Result<(), Error>, diff --git a/src/interpreter/builders/element.rs b/src/interpreter/builders/element.rs index d5d229e6..bf799e14 100644 --- a/src/interpreter/builders/element.rs +++ b/src/interpreter/builders/element.rs @@ -3,11 +3,11 @@ use std::ops::{Deref, DerefMut}; use tracing::instrument; use super::Update; -use crate::schema::xs::{ElementSubstitutionGroupType, ElementType, GroupType}; +use crate::schema::xs::{ElementSubstitutionGroupType, ElementType}; use crate::schema::Namespace; use crate::types::{ - DynamicInfo, ElementInfo, ElementMode, Ident, IdentType, Name, ReferenceInfo, Type, - TypeVariant, VecHelper, + DynamicInfo, ElementInfo, ElementMode, Ident, IdentType, ReferenceInfo, Type, TypeVariant, + VecHelper, }; use super::super::{Error, SchemaInterpreter}; @@ -255,27 +255,6 @@ impl<'a, 'schema, 'state> ElementBuilder<'a, 'schema, 'state> { inner(self, groups, &mut f) } - - fn make_field_name_and_type(&mut self, ty: &GroupType) -> (Name, Ident) { - let name = self - .state - .name_builder() - .generate_id() - .or(ty.name.clone()) - .remove_suffix("Type") - .remove_suffix("Content"); - let field_name = name.clone().shared_name("Content").finish(); - let type_name = name - .auto_extend2(false, true, self.state) - .remove_suffix("Type") - .remove_suffix("Content") - .shared_name("Content") - .with_id(true) - .finish(); - let type_ = Ident::new(type_name).with_ns(self.state.current_ns()); - - (field_name, type_) - } } impl<'schema, 'state> Deref for ElementBuilder<'_, 'schema, 'state> { diff --git a/src/interpreter/builders/simple_type.rs b/src/interpreter/builders/simple_type.rs index c9faa9ce..6a931404 100644 --- a/src/interpreter/builders/simple_type.rs +++ b/src/interpreter/builders/simple_type.rs @@ -3,10 +3,7 @@ use std::str::from_utf8; use tracing::instrument; -use crate::schema::xs::{ - ExtensionType, Facet, FacetType, GroupType, List, Restriction, RestrictionType, SimpleBaseType, - Union, Use, -}; +use crate::schema::xs::{Facet, FacetType, List, Restriction, SimpleBaseType, Union, Use}; use crate::schema::MaxOccurs; use crate::types::{ Base, Ident, IdentType, Name, ReferenceInfo, Type, TypeVariant, UnionTypeInfo, VariantInfo, @@ -135,48 +132,7 @@ impl<'a, 'schema, 'state> SimpleTypeBuilder<'a, 'schema, 'state> { } #[instrument(err, level = "trace", skip(self))] - fn apply_extension(&mut self, ty: &ExtensionType) -> Result<(), Error> { - use crate::schema::xs::ExtensionTypeContent as C; - - for c in &ty.content { - match c { - C::Annotation(_) | C::OpenContent(_) | C::Assert(_) => (), - C::All(_) - | C::AnyAttribute(_) - | C::Attribute(_) - | C::AttributeGroup(_) - | C::Choice(_) - | C::Group(_) - | C::Sequence(_) => unreachable!(), - } - } - - Ok(()) - } - - #[instrument(err, level = "trace", skip(self))] - fn apply_restriction(&mut self, ty: &RestrictionType) -> Result<(), Error> { - use crate::schema::xs::RestrictionTypeContent as C; - - for c in &ty.content { - match c { - C::Annotation(_) | C::OpenContent(_) | C::Assert(_) => (), - C::SimpleType(x) => self.apply_simple_type(x)?, - C::Facet(x) => self.apply_facet(x)?, - C::AnyAttribute(_) - | C::All(_) - | C::Attribute(_) - | C::AttributeGroup(_) - | C::Choice(_) - | C::Group(_) - | C::Sequence(_) => unreachable!(), - } - } - - Ok(()) - } - #[instrument(err, level = "trace", skip(self))] - fn apply_facet(&mut self, ty: &Facet) -> Result<(), Error> { + 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:#?}"), @@ -186,7 +142,7 @@ impl<'a, 'schema, 'state> SimpleTypeBuilder<'a, 'schema, 'state> { } #[instrument(err, level = "trace", skip(self))] - fn apply_enumeration(&mut self, ty: &FacetType) -> Result<(), Error> { + 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()) @@ -200,7 +156,7 @@ impl<'a, 'schema, 'state> SimpleTypeBuilder<'a, 'schema, 'state> { } #[instrument(err, level = "trace", skip(self))] - fn apply_union(&mut self, ty: &Union) -> Result<(), Error> { + pub fn apply_union(&mut self, ty: &Union) -> Result<(), Error> { let ui = get_or_init_any!(self, Union); if let Some(types) = &ty.member_types { @@ -288,27 +244,6 @@ impl<'a, 'schema, 'state> SimpleTypeBuilder<'a, 'schema, 'state> { Ok(()) } - - fn make_field_name_and_type(&mut self, ty: &GroupType) -> (Name, Ident) { - let name = self - .state - .name_builder() - .generate_id() - .or(ty.name.clone()) - .remove_suffix("Type") - .remove_suffix("Content"); - let field_name = name.clone().shared_name("Content").finish(); - let type_name = name - .auto_extend2(false, true, self.state) - .remove_suffix("Type") - .remove_suffix("Content") - .shared_name("Content") - .with_id(true) - .finish(); - let type_ = Ident::new(type_name).with_ns(self.state.current_ns()); - - (field_name, type_) - } } impl<'schema, 'state> Deref for SimpleTypeBuilder<'_, 'schema, 'state> { diff --git a/src/interpreter/builders/variant_type_xample.rs b/src/interpreter/builders/variant_type_xample.rs deleted file mode 100644 index 10b028c6..00000000 --- a/src/interpreter/builders/variant_type_xample.rs +++ /dev/null @@ -1,1181 +0,0 @@ -use std::borrow::Cow; -use std::collections::btree_map::Entry; -use std::ops::{Deref, DerefMut}; -use std::str::from_utf8; - -use tracing::instrument; - -use crate::schema::xs::{ - Any, AnyAttribute, AttributeGroupType, AttributeType, ComplexBaseType, ComplexContent, - ElementSubstitutionGroupType, ElementType, ExtensionType, Facet, FacetType, GroupType, List, - Restriction, RestrictionType, SimpleBaseType, SimpleContent, Union, Use, -}; -use crate::schema::{MaxOccurs, MinOccurs, Namespace}; -use crate::types::{ - AnyAttributeInfo, AnyInfo, AttributeInfo, Base, DynamicInfo, ElementInfo, ElementMode, Ident, - IdentType, Name, ReferenceInfo, Type, TypeVariant, UnionTypeInfo, VariantInfo, VecHelper, -}; - -use super::super::{Error, SchemaInterpreter}; - -#[derive(Debug)] -pub(crate) struct ComplexTypeBuilder<'a, 'schema, 'state> { - /// Type variant that is constructed by the builder - 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, - - /// `true` if the simple content type of a complex type was already duplicated - /// and is now unique for this type. - is_simple_content_unique: bool, - - 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, - Simple, - Complex, -} - -#[derive(Debug, Clone, Copy, Eq, PartialEq)] -enum UpdateMode { - Extension, - Restriction, -} - -#[derive(Debug, Clone, Copy)] -enum ComplexContentType { - All, - Choice, - 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> ComplexTypeBuilder<'a, 'schema, 'state> { - pub fn new(owner: &'a mut SchemaInterpreter<'schema, 'state>) -> Self { - Self { - variant: None, - fixed: false, - type_mode: TypeMode::Unknown, - content_mode: ContentMode::Unknown, - is_simple_content_unique: false, - owner, - } - } - - pub fn finish(self) -> Result { - let variant = self.variant.ok_or(Error::NoType)?; - - Ok(Type::new(variant)) - } - - #[instrument(err, level = "trace", skip(self))] - pub 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)?; - } - } - } - - 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)?; - } - - 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)?, - } - } - - 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:#?}"), - } - } - - Ok(()) - } - - #[instrument(err, level = "trace", skip(self))] - pub(super) 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); - - for c in &ty.content { - match c { - C::Annotation(_) | C::OpenContent(_) | C::Assert(_) => (), - C::ComplexContent(x) => { - let ci = get_or_init_any!(self, ComplexType); - ci.is_dynamic = ty.abstract_; - self.apply_complex_content(x)?; - } - C::SimpleContent(x) => self.apply_simple_content(x)?, - C::All(x) => self.apply_all(x)?, - C::Choice(x) => self.apply_choice(x)?, - C::Sequence(x) => self.apply_sequence(x)?, - C::Attribute(x) => self.apply_attribute_ref(x)?, - C::AnyAttribute(x) => self.apply_any_attribute(x)?, - C::Group(x) => self.apply_group_ref(x)?, - C::AttributeGroup(x) => self.apply_attribute_group_ref(x)?, - } - } - - Ok(()) - } - - #[instrument(err, level = "trace", skip(self))] - fn apply_simple_content(&mut self, ty: &SimpleContent) -> Result<(), Error> { - use crate::schema::xs::SimpleContentContent as C; - - self.content_mode = ContentMode::Simple; - - for c in &ty.content { - match c { - C::Annotation(_) => (), - C::Extension(x) => self.apply_simple_content_extension(x)?, - C::Restriction(x) => self.apply_simple_content_restriction(x)?, - } - } - - Ok(()) - } - - #[instrument(err, level = "trace", skip(self))] - fn apply_complex_content(&mut self, ty: &ComplexContent) -> Result<(), Error> { - use crate::schema::xs::ComplexContentContent as C; - - get_or_init_any!(self, ComplexType); - - for c in &ty.content { - match c { - C::Annotation(_) => (), - C::Extension(x) => self.apply_complex_content_extension(x)?, - C::Restriction(x) => self.apply_complex_content_restriction(x)?, - } - } - - Ok(()) - } - - #[instrument(err, level = "trace", skip(self))] - fn apply_simple_content_extension(&mut self, ty: &ExtensionType) -> Result<(), Error> { - let base = self.parse_qname(&ty.base)?; - - self.copy_base_type(&base, UpdateMode::Extension)?; - 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), - e => crate::unreachable!("Unexpected type: {e:#?}!"), - } - - Ok(()) - } - - #[instrument(err, level = "trace", skip(self))] - fn apply_simple_content_restriction(&mut self, ty: &RestrictionType) -> Result<(), Error> { - let base = self.parse_qname(&ty.base)?; - - self.copy_base_type(&base, UpdateMode::Restriction)?; - 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), - e => crate::unreachable!("Unexpected type: {e:#?}!"), - } - - Ok(()) - } - - #[instrument(err, level = "trace", skip(self))] - fn apply_complex_content_extension(&mut self, ty: &ExtensionType) -> Result<(), Error> { - let base = self.parse_qname(&ty.base)?; - - self.copy_base_type(&base, UpdateMode::Extension)?; - self.apply_extension(ty)?; - - let ci = get_or_init_any!(self, ComplexType); - ci.base = Base::Extension(base); - - Ok(()) - } - - #[instrument(err, level = "trace", skip(self))] - fn apply_complex_content_restriction(&mut self, ty: &RestrictionType) -> Result<(), Error> { - let base = self.parse_qname(&ty.base)?; - - self.copy_base_type(&base, UpdateMode::Restriction)?; - self.apply_restriction(ty)?; - - let ci = get_or_init_any!(self, ComplexType); - ci.base = Base::Restriction(base); - - Ok(()) - } - - #[instrument(err, level = "trace", skip(self))] - fn apply_extension(&mut self, ty: &ExtensionType) -> Result<(), Error> { - use crate::schema::xs::ExtensionTypeContent as C; - - for c in &ty.content { - match c { - C::Annotation(_) | C::OpenContent(_) | C::Assert(_) => (), - C::All(x) => self.apply_all(x)?, - C::AnyAttribute(x) => self.apply_any_attribute(x)?, - C::Attribute(x) => self.apply_attribute_ref(x)?, - C::AttributeGroup(x) => self.apply_attribute_group_ref(x)?, - C::Choice(x) => self.apply_choice(x)?, - C::Group(x) => self.apply_group_ref(x)?, - C::Sequence(x) => self.apply_sequence(x)?, - } - } - - Ok(()) - } - - #[instrument(err, level = "trace", skip(self))] - fn apply_restriction(&mut self, ty: &RestrictionType) -> Result<(), Error> { - use crate::schema::xs::RestrictionTypeContent as C; - - for c in &ty.content { - match c { - C::Annotation(_) | C::OpenContent(_) | C::Assert(_) => (), - C::All(x) => self.apply_all(x)?, - C::AnyAttribute(x) => self.apply_any_attribute(x)?, - C::Attribute(x) => self.apply_attribute_ref(x)?, - C::AttributeGroup(x) => self.apply_attribute_group_ref(x)?, - C::Choice(x) => self.apply_choice(x)?, - 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)?, - } - } - - Ok(()) - } - - #[instrument(err, level = "trace", skip(self))] - fn apply_all(&mut self, ty: &GroupType) -> Result<(), Error> { - let (field_name, type_ident) = self.make_field_name_and_type(ty); - - self.create_subtype_builder( - field_name, - ty.min_occurs, - ty.max_occurs, - type_ident, - ComplexContentType::All, - |builder| builder.apply_group(ty), - )?; - - Ok(()) - } - - #[instrument(err, level = "trace", skip(self))] - fn apply_choice(&mut self, ty: &GroupType) -> Result<(), Error> { - let (field_name, type_ident) = self.make_field_name_and_type(ty); - - self.create_subtype_builder( - field_name, - ty.min_occurs, - ty.max_occurs, - type_ident, - ComplexContentType::Choice, - |builder| builder.apply_group(ty), - )?; - - Ok(()) - } - - #[instrument(err, level = "trace", skip(self))] - fn apply_sequence(&mut self, ty: &GroupType) -> Result<(), Error> { - let (field_name, type_ident) = self.make_field_name_and_type(ty); - - self.create_subtype_builder( - field_name, - ty.min_occurs, - ty.max_occurs, - type_ident, - ComplexContentType::Sequence, - |builder| builder.apply_group(ty), - )?; - - Ok(()) - } - - #[instrument(err, level = "trace", skip(self))] - fn apply_group(&mut self, ty: &GroupType) -> Result<(), Error> { - use crate::schema::xs::GroupTypeContent as C; - - for c in &ty.content { - match c { - C::Annotation(_) => (), - C::All(x) => self.apply_all(x)?, - C::Choice(x) => self.apply_choice(x)?, - C::Sequence(x) => self.apply_sequence(x)?, - C::Any(x) => self.apply_any(x)?, - C::Group(x) => self.apply_group_ref(x)?, - C::Element(x) => self.apply_element_ref(x)?, - } - } - - Ok(()) - } - - #[instrument(err, level = "trace", skip(self))] - fn apply_element_ref(&mut self, ty: &ElementType) -> Result<(), Error> { - match ty { - ElementType { - ref_: Some(ref_), - name, - .. - } => { - let type_ = self.parse_qname(ref_)?.with_type(IdentType::Element); - let name = self.state.name_builder().or(name).or(&type_.name).finish(); - let ident = Ident::new(name) - .with_ns(type_.ns) - .with_type(IdentType::Element); - - let ci = get_or_init_type!(self, Sequence); - let element = ci.elements.find_or_insert(ident, |ident| { - ElementInfo::new(ident, type_, ElementMode::Element) - }); - crate::assert_eq!(element.element_mode, ElementMode::Element); - element.update(ty); - } - ty => { - let field_name = self.state.name_builder().or(&ty.name).finish(); - let field_ident = Ident::new(field_name) - .with_ns(self.state.current_ns()) - .with_type(IdentType::Element); - let type_name = self - .state - .name_builder() - .extend(true, ty.name.clone()) - .auto_extend2(true, false, self.state); - let type_name = if type_name.has_extension() { - type_name.with_id(false) - } else { - type_name.shared_name("Temp") - }; - let type_name = type_name.finish(); - - 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 element = ci.elements.find_or_insert(field_ident, |ident| { - ElementInfo::new(ident, type_, ElementMode::Element) - }); - crate::assert_eq!(element.element_mode, ElementMode::Element); - element.update(ty); - } - } - - Ok(()) - } - - #[instrument(err, level = "trace", skip(self))] - fn apply_group_ref(&mut self, ty: &GroupType) -> Result<(), Error> { - use crate::schema::xs::GroupTypeContent as C; - - let ref_ = ty.ref_.as_ref().ok_or(Error::GroupMissingRef)?; - let ref_ = self.parse_qname(ref_)?.with_type(IdentType::Group); - let group = self - .find_group(ref_.clone()) - .ok_or(Error::UnknownElement(ref_))?; - - self.state.type_stack.push(None); - - for c in &group.content { - match c { - C::Annotation(_) => (), - C::Any(x) => self.apply_any(x)?, - C::All(x) => self.apply_all(&x.patch(ty))?, - C::Choice(x) => self.apply_choice(&x.patch(ty))?, - C::Sequence(x) => self.apply_sequence(&x.patch(ty))?, - C::Group(x) => self.apply_group_ref(x)?, - C::Element(x) => self.apply_element_ref(x)?, - } - } - - self.state.type_stack.pop(); - - Ok(()) - } - - #[instrument(err, level = "trace", skip(self))] - fn apply_attribute_group_ref(&mut self, ty: &AttributeGroupType) -> Result<(), Error> { - use crate::schema::xs::AttributeGroupTypeContent as C; - - let ref_ = ty.ref_.as_ref().ok_or(Error::AttributeGroupMissingRef)?; - let ref_ = self.parse_qname(ref_)?.with_type(IdentType::AttributeGroup); - let group = self - .find_attribute_group(ref_.clone()) - .ok_or(Error::UnknownElement(ref_))?; - - self.state.type_stack.push(None); - - for c in &group.content { - match c { - C::Annotation(_) => (), - C::Attribute(x) => self.apply_attribute_ref(x)?, - C::AnyAttribute(x) => self.apply_any_attribute(x)?, - C::AttributeGroup(x) => self.apply_attribute_group_ref(x)?, - } - } - - self.state.type_stack.pop(); - - 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 = get_or_init_any!(self, ComplexType); - 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 = get_or_init_any!(self, ComplexType); - 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_extend2(true, true, self.state) - .finish(); - let ns = self.state.current_ns(); - - self.create_simple_type(ns, Some(type_name), 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 = get_or_init_any!(self, ComplexType); - 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(()) - } - - #[instrument(err, level = "trace", skip(self))] - fn apply_any(&mut self, ty: &Any) -> Result<(), Error> { - let si = get_or_init_type!(self, Sequence); - si.any.create_or_update(ty); - - Ok(()) - } - - #[instrument(err, level = "trace", skip(self))] - fn apply_any_attribute(&mut self, ty: &AnyAttribute) -> Result<(), Error> { - let ci = get_or_init_any!(self, ComplexType); - ci.any_attribute.create_or_update(ty); - - Ok(()) - } - - #[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_extend2(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(()) - } - - 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; - - 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()); - - ty - } - Err(Error::UnknownType(_)) => { - self.fixed = true; - - self.owner.get_complex_type_variant(base)? - } - Err(error) => Err(error)?, - } - } - (TypeMode::Complex, ContentMode::Complex) => { - self.owner.get_complex_type_variant(base)? - } - (_, _) => crate::unreachable!("Unset or invalid combination!"), - }; - - tracing::debug!("{base:#?}"); - - let mut base = base.clone(); - - match (self.content_mode, &mut base) { - (ContentMode::Simple, TypeVariant::Enumeration(ei)) => ei.variants.clear(), - (ContentMode::Complex, TypeVariant::ComplexType(ci)) => { - if let Some(content_ident) = &ci.content { - let mut content_type = self - .owner - .state - .types - .get(content_ident) - .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) => { - si.elements.retain(|element| element.min_occurs > 0); - - if matches!( - si.any, - Some(AnyInfo { - min_occurs: Some(0), - .. - }) - ) { - si.any = None; - } - } - (_, UpdateMode::Extension) => (), - (_, _) => tracing::warn!("Complex type does not has `All`, `Choice` or `Sequence` as content: {content_ident:#?} => {content_type:#?}!"), - } - - let content_name = self.state.make_content_name(); - let content_ident = Ident::new(content_name).with_ns(self.state.current_ns()); - - self.state - .add_type(content_ident.clone(), content_type, false)?; - - ci.content = Some(content_ident); - } - } - (_, _) => (), - } - - 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); - ci.content.get_or_insert(base_ident); - } - (None, TypeMode::Complex, ContentMode::Simple | ContentMode::Complex) => { - self.variant = Some(base); - } - (_, _, _) => crate::unreachable!("Unset or invalid combination!"), - } - - tracing::debug!("{:#?}", self.variant); - - 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 ComplexTypeBuilder<'x, 'y, 'z>, - groups: &ElementSubstitutionGroupType, - f: &mut F, - ) -> Result<(), Error> - where - F: FnMut(&mut ComplexTypeBuilder<'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 ComplexTypeBuilder<'_, '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 - ); - }; - - let content = self.owner.get_simple_type_variant(&content_ident)?.clone(); - if !self.is_simple_content_unique { - self.is_simple_content_unique = true; - let content_name = self.owner.state.make_content_name(); - content_ident = Ident::new(content_name).with_ns(self.owner.state.current_ns()); - - ci.content = Some(content_ident.clone()); - } - - let mut builder = ComplexTypeBuilder::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); - - match self.owner.state.types.entry(content_ident) { - Entry::Vacant(e) => { - e.insert(content); - } - Entry::Occupied(e) => { - *e.into_mut() = content; - } - } - } - (TypeMode::Complex, ContentMode::Complex) => { - crate::unreachable!("Complex type with complex content tried to access simple content builder: {:?}", &self.variant); - } - (_, _) => crate::unreachable!("Unset or invalid combination!"), - } - - Ok(()) - } - - #[instrument(err, level = "trace", skip(self, f))] - fn create_subtype_builder( - &mut self, - field_name: Name, - min_occurs: MinOccurs, - max_occurs: MaxOccurs, - type_ident: Ident, - complex_content_type: ComplexContentType, - f: F, - ) -> Result<(), Error> - where - F: FnOnce(&mut ComplexTypeBuilder<'_, 'schema, 'state>) -> Result<(), Error>, - { - enum UpdateContentMode { - Unknown, - Update, - Append, - } - - let mut variant = None; - let mut update_content_mode = UpdateContentMode::Unknown; - - if let Some(TypeVariant::ComplexType(ci)) = &self.variant { - if let Some(content_ident) = &ci.content { - let content_ty = self - .owner - .state - .types - .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()); - update_content_mode = UpdateContentMode::Update; - } - (_, _) => update_content_mode = UpdateContentMode::Append, - } - } - } - - 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()), - }); - - let mut builder = ComplexTypeBuilder::new(&mut *self.owner); - builder.type_mode = self.type_mode; - builder.variant = Some(variant); - - f(&mut builder)?; - - let ty = builder.finish()?; - - let (TypeVariant::All(si) | TypeVariant::Choice(si) | TypeVariant::Sequence(si)) = - &ty.variant - else { - return Err(Error::ExpectedGroupType); - }; - - if si.elements.is_empty() && si.any.is_none() { - return Ok(()); - } - - let ns = self.state.current_ns(); - - match &mut self.variant { - Some(TypeVariant::ComplexType(ci)) => match update_content_mode { - UpdateContentMode::Unknown => { - self.owner.state.add_type(type_ident.clone(), ty, false)?; - - ci.content = Some(type_ident); - ci.min_occurs = ci.min_occurs.min(min_occurs); - ci.max_occurs = ci.max_occurs.max(max_occurs); - } - UpdateContentMode::Update => { - let content_ident = ci.content.as_ref().unwrap(); - - self.owner.state.types.insert(content_ident.clone(), ty); - - ci.min_occurs = ci.min_occurs.min(min_occurs); - ci.max_occurs = ci.max_occurs.max(max_occurs); - } - UpdateContentMode::Append => { - self.owner.state.add_type(type_ident.clone(), ty, false)?; - - 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 (TypeVariant::All(si) - | TypeVariant::Choice(si) - | TypeVariant::Sequence(si)) = content_variant - else { - unreachable!(); - }; - - let ident = Ident::new(field_name) - .with_ns(ns) - .with_type(IdentType::Group); - let element = si.elements.find_or_insert(ident, |ident| { - ElementInfo::new(ident, type_ident, ElementMode::Group) - }); - - element.min_occurs = element.min_occurs.min(min_occurs); - element.max_occurs = element.max_occurs.max(max_occurs); - } - }, - Some(TypeVariant::All(si) | TypeVariant::Choice(si) | TypeVariant::Sequence(si)) => { - self.owner.state.add_type(type_ident.clone(), ty, false)?; - - let ident = Ident::new(field_name) - .with_ns(ns) - .with_type(IdentType::Group); - let element = si.elements.find_or_insert(ident, |ident| { - ElementInfo::new(ident, type_ident, ElementMode::Group) - }); - - element.min_occurs = element.min_occurs.min(min_occurs); - element.max_occurs = element.max_occurs.max(max_occurs); - } - None => { - self.owner.state.add_type(type_ident.clone(), ty, false)?; - - let ci = get_or_init_any!(self, ComplexType); - - ci.content = Some(type_ident); - ci.min_occurs = ci.min_occurs.min(min_occurs); - ci.max_occurs = ci.max_occurs.max(max_occurs); - } - e => crate::unreachable!("{:?}", e), - } - - Ok(()) - } - - fn make_field_name_and_type(&mut self, ty: &GroupType) -> (Name, Ident) { - let name = self - .state - .name_builder() - .generate_id() - .or(ty.name.clone()) - .remove_suffix("Type") - .remove_suffix("Content"); - let field_name = name.clone().shared_name("Content").finish(); - let type_name = name - .auto_extend2(false, true, self.state) - .remove_suffix("Type") - .remove_suffix("Content") - .shared_name("Content") - .with_id(true) - .finish(); - let type_ = Ident::new(type_name).with_ns(self.state.current_ns()); - - (field_name, type_) - } -} - -impl<'schema, 'state> Deref for ComplexTypeBuilder<'_, 'schema, 'state> { - type Target = SchemaInterpreter<'schema, 'state>; - - fn deref(&self) -> &Self::Target { - self.owner - } -} - -impl DerefMut for ComplexTypeBuilder<'_, '_, '_> { - fn deref_mut(&mut self) -> &mut Self::Target { - self.owner - } -} From 84b3ddea742c459358a1414490e1c40fdf8f2959 Mon Sep 17 00:00:00 2001 From: Lukas Friman Date: Wed, 23 Apr 2025 20:19:12 +0200 Subject: [PATCH 05/12] Separated SimpleTypes from ComplexTypes. --- src/generator/data.rs | 167 ++++++----- src/generator/helper.rs | 47 ++- src/generator/misc.rs | 39 ++- src/generator/mod.rs | 20 +- .../renderer/quick_xml/deserialize.rs | 10 +- src/interpreter/builders/attribute_type.rs | 14 +- src/interpreter/builders/complex_type.rs | 116 +++++--- src/interpreter/builders/element.rs | 57 ++-- src/interpreter/builders/simple_type.rs | 30 +- src/interpreter/mod.rs | 66 ++++- src/interpreter/schema.rs | 70 ++--- src/misc.rs | 147 +++++++--- src/optimizer/dynamic_to_choice.rs | 28 +- src/optimizer/empty_enums.rs | 13 +- src/optimizer/empty_unions.rs | 13 +- src/optimizer/flatten_complex_type.rs | 43 +-- src/optimizer/flatten_unions.rs | 20 +- src/optimizer/merge_choice_cardinality.rs | 14 +- src/optimizer/merge_enum_unions.rs | 41 +-- src/optimizer/misc/base_map.rs | 39 ++- src/optimizer/misc/typedef_map.rs | 14 +- src/optimizer/remove_duplicates.rs | 17 +- src/optimizer/resolve_typedefs.rs | 47 +-- src/optimizer/unrestricted_base.rs | 10 +- src/types/info/complex.rs | 31 +- src/types/mod.rs | 127 ++++++-- src/types/type_.rs | 272 ++++++++++++++++-- tests/feature/type_name_clash/mod.rs | 4 +- 28 files changed, 1057 insertions(+), 459 deletions(-) diff --git a/src/generator/data.rs b/src/generator/data.rs index 388733ce..495af881 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, + 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!() + }}, }) } } @@ -658,39 +685,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(|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)) } - }; + }).unwrap_or(Ok((TypeMode::Sequence, &[][..], None)))?; Self::new( req, @@ -1008,7 +1035,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; } @@ -1279,41 +1306,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 +1373,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 +1389,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 +1399,6 @@ impl<'a, 'types> Request<'a, 'types> { } _ => (), }, - - _ => (), } Err(Error::InvalidDefaultValue( @@ -1384,14 +1419,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, } } @@ -1418,11 +1453,11 @@ fn make_derived_type_data<'types>( let s_name = ident.name.to_string(); let b_name = Literal::byte_string(s_name.as_bytes()); - let ty = req + let complex_ty = req .types - .get(ident) + .get_complex_type(ident) .ok_or_else(|| Error::UnknownType(ident.clone()))?; - let base_ident = if let TypeVariant::Dynamic(di) = &ty.variant { + let base_ident = if let ComplexTypeVariant::Dynamic(di) = &complex_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..35b81ed5 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, ty) in types.complex_types_iter() { + let ComplexTypeVariant::Dynamic(ai) = &ty.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 index fa80fd9a..93793238 100644 --- a/src/interpreter/builders/attribute_type.rs +++ b/src/interpreter/builders/attribute_type.rs @@ -5,7 +5,8 @@ use tracing::instrument; use super::Update; use crate::schema::xs::AttributeType; use crate::types::{ - AttributeInfo, Ident, IdentType, Name, ReferenceInfo, Type, TypeVariant, VecHelper, + AttributeInfo, ComplexType, ComplexTypeVariant, Ident, IdentType, Name, ReferenceInfo, Type, + VecHelper, }; use super::super::{Error, SchemaInterpreter}; @@ -16,7 +17,7 @@ pub(crate) struct AttributeTypeBuilder<'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, @@ -29,10 +30,10 @@ pub(crate) struct AttributeTypeBuilder<'a, 'schema, 'state> { /// Initialize the type of a `$builder` to any type `$variant`. macro_rules! init_any { ($builder:expr, $variant:ident, $value:expr, $fixed:expr) => {{ - $builder.variant = Some(TypeVariant::$variant($value)); + $builder.variant = Some(ComplexTypeVariant::$variant($value)); $builder.fixed = $fixed; - let TypeVariant::$variant(ret) = $builder.variant.as_mut().unwrap() else { + let ComplexTypeVariant::$variant(ret) = $builder.variant.as_mut().unwrap() else { crate::unreachable!(); }; @@ -48,7 +49,7 @@ macro_rules! get_or_init_any { ($builder:expr, $variant:ident, $default:expr) => { match &mut $builder.variant { None => init_any!($builder, $variant, $default, true), - Some(TypeVariant::$variant(ret)) => ret, + Some(ComplexTypeVariant::$variant(ret)) => ret, _ if !$builder.fixed => init_any!($builder, $variant, $default, true), Some(e) => crate::unreachable!("Type is expected to be a {:?}", e), } @@ -68,9 +69,8 @@ impl<'a, 'schema, 'state> AttributeTypeBuilder<'a, 'schema, 'state> { } pub(crate) fn finish(self) -> Result { - println!("AttributeTypeBuilder::finish"); self.type_ - .or_else(|| self.variant.map(Type::new)) + .or_else(|| self.variant.map(ComplexType::new).map(Type::ComplexType)) .ok_or(Error::NoType) } diff --git a/src/interpreter/builders/complex_type.rs b/src/interpreter/builders/complex_type.rs index 1ad40ed3..1fe0db25 100644 --- a/src/interpreter/builders/complex_type.rs +++ b/src/interpreter/builders/complex_type.rs @@ -10,9 +10,10 @@ use crate::schema::xs::{ ElementType, ExtensionType, Facet, GroupType, RestrictionType, SimpleContent, }; use crate::schema::{MaxOccurs, MinOccurs}; +use crate::types::type_::TypeVariant; use crate::types::{ - AnyInfo, AttributeInfo, Base, ElementInfo, ElementMode, Ident, IdentType, Name, Type, - TypeVariant, VecHelper, + AnyInfo, AttributeInfo, Base, ComplexType, ComplexTypeVariant, ElementInfo, ElementMode, Ident, + IdentType, Name, SimpleType, SimpleTypeVariant, Type, VecHelper, }; use super::super::{Error, SchemaInterpreter}; @@ -22,7 +23,7 @@ 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, @@ -62,10 +63,10 @@ enum ComplexContentType { /// Initialize the type of a `$builder` to any type `$variant`. macro_rules! init_any { ($builder:expr, $variant:ident, $value:expr, $fixed:expr) => {{ - $builder.variant = Some(TypeVariant::$variant($value)); + $builder.variant = Some(ComplexTypeVariant::$variant($value)); $builder.fixed = $fixed; - let TypeVariant::$variant(ret) = $builder.variant.as_mut().unwrap() else { + let ComplexTypeVariant::$variant(ret) = $builder.variant.as_mut().unwrap() else { crate::unreachable!(); }; @@ -81,7 +82,7 @@ macro_rules! get_or_init_any { ($builder:expr, $variant:ident, $default:expr) => { match &mut $builder.variant { None => init_any!($builder, $variant, $default, true), - Some(TypeVariant::$variant(ret)) => ret, + Some(ComplexTypeVariant::$variant(ret)) => ret, _ if !$builder.fixed => init_any!($builder, $variant, $default, true), Some(e) => crate::unreachable!("Type is expected to be a {:?}", e), } @@ -96,7 +97,11 @@ macro_rules! get_or_init_type { ($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, + Some( + ComplexTypeVariant::All(si) + | ComplexTypeVariant::Choice(si) + | ComplexTypeVariant::Sequence(si), + ) => si, _ if !$builder.fixed => init_any!($builder, $variant, $default, true), Some(e) => crate::unreachable!("Type is expected to be a {:?}", e), } @@ -119,7 +124,7 @@ impl<'a, 'schema, 'state> ComplexTypeBuilder<'a, 'schema, 'state> { pub(crate) fn finish(self) -> Result { self.type_ - .or_else(|| self.variant.map(Type::new)) + .or_else(|| self.variant.map(ComplexType::new).map(Type::ComplexType)) .ok_or(Error::NoType) } @@ -195,10 +200,10 @@ impl<'a, 'schema, 'state> ComplexTypeBuilder<'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:#?}!"), } @@ -213,10 +218,10 @@ impl<'a, 'schema, 'state> ComplexTypeBuilder<'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:#?}!"), } @@ -572,26 +577,33 @@ impl<'a, 'schema, 'state> ComplexTypeBuilder<'a, 'schema, 'state> { simple_base_ident = Some(base.clone()); - ty + TypeVariant::SimpleType(ty) } Err(Error::UnknownType(_)) => { self.fixed = true; - self.owner.get_complex_type_variant(base)? + TypeVariant::ComplexType(self.owner.get_complex_type_variant(base)?) } Err(error) => Err(error)?, }, - ContentMode::Complex => self.owner.get_complex_type_variant(base)?, + ContentMode::Complex => { + TypeVariant::ComplexType(self.owner.get_complex_type_variant(base)?) + } _ => 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 @@ -601,8 +613,8 @@ impl<'a, 'schema, 'state> ComplexTypeBuilder<'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!( @@ -637,7 +649,7 @@ impl<'a, 'schema, 'state> ComplexTypeBuilder<'a, 'schema, 'state> { ci.content.get_or_insert(base_ident); } (None, ContentMode::Simple | ContentMode::Complex) => { - self.variant = Some(base); + self.variant = Some(base.into_complex_type_variant()); } (_, _) => crate::unreachable!("Unset or invalid combination!"), } @@ -677,7 +689,7 @@ impl<'a, 'schema, 'state> ComplexTypeBuilder<'a, 'schema, 'state> { 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) => { @@ -719,7 +731,7 @@ impl<'a, 'schema, 'state> ComplexTypeBuilder<'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 @@ -728,11 +740,20 @@ impl<'a, 'schema, 'state> ComplexTypeBuilder<'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, @@ -741,9 +762,9 @@ impl<'a, 'schema, 'state> ComplexTypeBuilder<'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 = ComplexTypeBuilder::new(&mut *self.owner); @@ -753,8 +774,11 @@ impl<'a, 'schema, 'state> ComplexTypeBuilder<'a, 'schema, 'state> { 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); }; @@ -766,7 +790,7 @@ impl<'a, 'schema, 'state> ComplexTypeBuilder<'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)?; @@ -787,11 +811,13 @@ impl<'a, 'schema, 'state> ComplexTypeBuilder<'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!(); }; @@ -807,7 +833,11 @@ impl<'a, 'schema, 'state> ComplexTypeBuilder<'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) diff --git a/src/interpreter/builders/element.rs b/src/interpreter/builders/element.rs index bf799e14..7cce5f92 100644 --- a/src/interpreter/builders/element.rs +++ b/src/interpreter/builders/element.rs @@ -6,8 +6,8 @@ use super::Update; use crate::schema::xs::{ElementSubstitutionGroupType, ElementType}; use crate::schema::Namespace; use crate::types::{ - DynamicInfo, ElementInfo, ElementMode, Ident, IdentType, ReferenceInfo, Type, TypeVariant, - VecHelper, + ComplexType, ComplexTypeVariant, DynamicInfo, ElementInfo, ElementMode, Ident, IdentType, + ReferenceInfo, SimpleTypeVariant, Type, TypeDescriptor, VecHelper, }; use super::super::{Error, SchemaInterpreter}; @@ -15,7 +15,7 @@ use super::super::{Error, SchemaInterpreter}; #[derive(Debug)] pub(crate) struct ElementBuilder<'a, 'schema, 'state> { /// 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, @@ -31,10 +31,10 @@ macro_rules! init_any { init_any!($builder, $variant, Default::default(), true) }; ($builder:expr, $variant:ident, $value:expr, $fixed:expr) => {{ - $builder.variant = Some(TypeVariant::$variant($value)); + $builder.variant = Some(ComplexTypeVariant::$variant($value)); $builder.fixed = $fixed; - let TypeVariant::$variant(ret) = $builder.variant.as_mut().unwrap() else { + let ComplexTypeVariant::$variant(ret) = $builder.variant.as_mut().unwrap() else { crate::unreachable!(); }; @@ -50,7 +50,11 @@ macro_rules! get_or_init_type { ($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, + Some( + ComplexTypeVariant::All(si) + | ComplexTypeVariant::Choice(si) + | ComplexTypeVariant::Sequence(si), + ) => si, _ if !$builder.fixed => init_any!($builder, $variant, $default, true), Some(e) => crate::unreachable!("Type is expected to be a {:?}", e), } @@ -69,10 +73,10 @@ impl<'a, 'schema, 'state> ElementBuilder<'a, 'schema, 'state> { } pub(crate) fn finish(self) -> Result { - println!("ElementBuilder::finish"); - let variant = self.variant.ok_or(Error::NoType)?; - - Ok(Type::new(variant)) + self.variant + .map(ComplexType::new) + .map(Type::ComplexType) + .ok_or(Error::NoType) } #[instrument(err, level = "trace", skip(self))] @@ -136,7 +140,7 @@ impl<'a, 'schema, 'state> ElementBuilder<'a, 'schema, 'state> { if ty.abstract_ { let type_ = match self.variant.take() { None => None, - Some(TypeVariant::Reference(ti)) => Some(ti.type_), + Some(ComplexTypeVariant::Reference(ti)) => Some(ti.type_), e => crate::unreachable!("Unexpected type: {:?}", e), }; @@ -147,16 +151,37 @@ impl<'a, 'schema, 'state> ElementBuilder<'a, 'schema, 'state> { 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 { + let mut 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), + .. + }) = &mut 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 TypeVariant::Dynamic(ai) = &mut base_ty.variant else { + let Type::ComplexType(TypeDescriptor { + variant: ComplexTypeVariant::Dynamic(ai), + .. + }) = &mut base_ty + else { return Err(Error::ExpectedDynamicElement(base_ident.clone())); }; diff --git a/src/interpreter/builders/simple_type.rs b/src/interpreter/builders/simple_type.rs index 6a931404..ea011199 100644 --- a/src/interpreter/builders/simple_type.rs +++ b/src/interpreter/builders/simple_type.rs @@ -6,8 +6,8 @@ use tracing::instrument; use crate::schema::xs::{Facet, FacetType, List, Restriction, SimpleBaseType, Union, Use}; use crate::schema::MaxOccurs; use crate::types::{ - Base, Ident, IdentType, Name, ReferenceInfo, Type, TypeVariant, UnionTypeInfo, VariantInfo, - VecHelper, + Base, Ident, IdentType, Name, ReferenceInfo, SimpleType, SimpleTypeVariant, Type, + UnionTypeInfo, VariantInfo, VecHelper, }; use super::super::{Error, SchemaInterpreter}; @@ -15,7 +15,7 @@ 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, + pub variant: Option, /// `true` if `type_` is fixed and can not be changed anymore pub fixed: bool, @@ -35,10 +35,10 @@ enum UpdateMode { /// Initialize the type of a `$builder` to any type `$variant`. macro_rules! init_any { ($builder:expr, $variant:ident, $value:expr, $fixed:expr) => {{ - $builder.variant = Some(TypeVariant::$variant($value)); + $builder.variant = Some(SimpleTypeVariant::$variant($value)); $builder.fixed = $fixed; - let TypeVariant::$variant(ret) = $builder.variant.as_mut().unwrap() else { + let SimpleTypeVariant::$variant(ret) = $builder.variant.as_mut().unwrap() else { crate::unreachable!(); }; @@ -54,7 +54,7 @@ macro_rules! get_or_init_any { ($builder:expr, $variant:ident, $default:expr) => { match &mut $builder.variant { None => init_any!($builder, $variant, $default, true), - Some(TypeVariant::$variant(ret)) => ret, + Some(SimpleTypeVariant::$variant(ret)) => ret, _ if !$builder.fixed => init_any!($builder, $variant, $default, true), Some(e) => crate::unreachable!("Type is expected to be a {:?}", e), } @@ -73,9 +73,10 @@ impl<'a, 'schema, 'state> SimpleTypeBuilder<'a, 'schema, 'state> { } pub(crate) fn finish(self) -> Result { - let variant = self.variant.ok_or(Error::NoType)?; - - Ok(Type::new(variant)) + self.variant + .map(SimpleType::new) + .map(Type::SimpleType) + .ok_or(Error::NoType) } #[instrument(err, level = "trace", skip(self))] @@ -120,10 +121,9 @@ impl<'a, 'schema, 'state> SimpleTypeBuilder<'a, 'schema, 'state> { 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), + 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:#?}"), } } @@ -234,8 +234,8 @@ impl<'a, 'schema, 'state> SimpleTypeBuilder<'a, 'schema, 'state> { let mut base = base.clone(); - if let TypeVariant::Enumeration(ei) = &mut base { - ei.variants.clear() + if let SimpleTypeVariant::Enumeration(ei) = &mut base { + ei.variants.clear(); } self.variant = Some(base); diff --git a/src/interpreter/mod.rs b/src/interpreter/mod.rs index d4926a08..e68b4a0c 100644 --- a/src/interpreter/mod.rs +++ b/src/interpreter/mod.rs @@ -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, SimpleTypeVariant, Type, Types, }; pub use error::Error; @@ -67,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) } @@ -87,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, + )?; }; } @@ -132,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, )?; }; @@ -141,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, )?; }; @@ -231,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), @@ -240,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), @@ -256,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 cdf7d3e1..f51e79fe 100644 --- a/src/interpreter/schema.rs +++ b/src/interpreter/schema.rs @@ -9,7 +9,7 @@ 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::{builders, Error, Node, State}; @@ -97,39 +97,34 @@ impl SchemaInterpreter<'_, '_> { } #[instrument(level = "trace", skip(self))] - pub(crate) 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> { + println!("get_simple_type_variant: {ident}"); if !self.state.types.contains_key(ident) { let ty = self .find_simple_type(ident.clone()) .ok_or_else(|| Error::UnknownType(ident.clone()))?; + println!("get_simple_type_variant type: {ty:#?}"); let new_ident = self.create_simple_type(ident.ns, None, None, ty)?; + println!("get_simple_type_variant new_ident: {new_ident}"); 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(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()) @@ -139,22 +134,11 @@ impl SchemaInterpreter<'_, '_> { 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())) } } @@ -174,8 +158,8 @@ impl SchemaInterpreter<'_, '_> { type_: IdentType::Element, }; - self.create_type_new(ident.clone(), move |mut owner| { - let mut builder = builders::ElementBuilder::new(owner.deref_mut()); + self.create_type_new(ident.clone(), move |owner| { + let mut builder = builders::ElementBuilder::new(owner); builder.apply_element(ty)?; let type_ = builder.finish()?; @@ -196,8 +180,8 @@ impl SchemaInterpreter<'_, '_> { type_: IdentType::Attribute, }; - self.create_type_new(ident.clone(), move |mut owner| { - let mut builder = builders::AttributeTypeBuilder::new(owner.deref_mut()); + self.create_type_new(ident.clone(), move |owner| { + let mut builder = builders::AttributeTypeBuilder::new(owner); builder.apply_attribute(ty)?; let type_ = builder.finish()?; @@ -219,8 +203,8 @@ impl SchemaInterpreter<'_, '_> { type_: ident_type.unwrap_or(IdentType::Type), }; - self.create_type_new(ident.clone(), move |mut owner| { - let mut builder = builders::SimpleTypeBuilder::new(owner.deref_mut()); + self.create_type_new(ident.clone(), move |owner| { + let mut builder = builders::SimpleTypeBuilder::new(owner); builder.apply_simple_type(ty)?; let type_ = builder.finish()?; @@ -242,8 +226,8 @@ impl SchemaInterpreter<'_, '_> { type_: ident_type.unwrap_or(IdentType::Type), }; - self.create_type_new(ident.clone(), move |mut owner| { - let mut builder = builders::ComplexTypeBuilder::new(owner.deref_mut()); + self.create_type_new(ident.clone(), move |owner| { + let mut builder = builders::ComplexTypeBuilder::new(owner); builder.apply_complex_type(ty)?; let type_ = builder.finish()?; diff --git a/src/misc.rs b/src/misc.rs index 1f8c686f..d972d747 100644 --- a/src/misc.rs +++ b/src/misc.rs @@ -6,7 +6,8 @@ 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::type_::{ComplexTypeVariant, SimpleTypeVariant}; +use crate::types::{ElementMode, Ident, Type, Types}; use crate::{GeneratorError, InterpreterError, OptimizerError, ParserError}; /// Trait that adds namespace information to a type. @@ -173,19 +174,14 @@ impl<'a> TypesPrinter<'a> { } #[allow(clippy::too_many_lines)] - fn print_type( + fn print_simple_type( &self, f: &mut Formatter<'_>, s: &mut State, ident: &Ident, - ty: &Type, + display_name: &Option, + 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 +189,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 +217,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, + 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 +365,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 +423,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, &ty.variant)? + } + Type::ComplexType(ty) => { + self.print_complex_type(f, s, ident, &ty.display_name, &ty.variant)? + } } s.visit.remove(ident); diff --git a/src/optimizer/dynamic_to_choice.rs b/src/optimizer/dynamic_to_choice.rs index fadffa76..03ce31e6 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, + type_::{ComplexTypeVariant, TypeDescriptor}, + ComplexInfo, ElementInfo, ElementMode, GroupInfo, Ident, Type, 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,10 +58,19 @@ 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 x = match variant { + ComplexTypeVariant::Dynamic(x) => x, + _ => crate::unreachable!(), + }; + let mut si = GroupInfo::default(); for derived in &x.derived_types { si.elements.find_or_insert(derived.clone(), |ident| { @@ -62,7 +78,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 +86,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..6abc521f 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::{type_::SimpleTypeVariant, Name, ReferenceInfo, 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 (_, type_) in types.simple_types_iter_mut() { + if let SimpleTypeVariant::Enumeration(x) = &mut type_.variant { x.variants .retain(|x| !matches!(&x.ident.name, Name::Named(x) if x.is_empty())); } @@ -72,11 +72,12 @@ 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 (_, type_) in types.simple_types_iter_mut() { + if let SimpleTypeVariant::Enumeration(x) = &mut type_.variant { if x.variants.is_empty() { if let Some(base) = x.base.as_ident() { - type_.variant = TypeVariant::Reference(ReferenceInfo::new(base.clone())); + type_.variant = + SimpleTypeVariant::Reference(ReferenceInfo::new(base.clone())); } } } diff --git a/src/optimizer/empty_unions.rs b/src/optimizer/empty_unions.rs index 9e6be294..72e06ec7 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::{type_::SimpleTypeVariant, ReferenceInfo, 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 (_, type_) in types.simple_types_iter_mut() { + if let SimpleTypeVariant::Union(x) = &mut type_.variant { let mut i = 0; let mut types_ = HashSet::new(); @@ -84,12 +84,13 @@ 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 (_, type_) in types.simple_types_iter_mut() { + if let SimpleTypeVariant::Union(x) = &type_.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())); + type_.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..2263810b 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::{type_::{ComplexTypeVariant, TypeDescriptor}, ElementInfo, ElementMode, GroupInfo, Ident, Type, Types}, }; use super::{Error, TypeTransformer}; @@ -36,9 +36,9 @@ impl TypeTransformer for FlattenComplexTypes { let idents = types - .iter() + .complex_types_iter() .filter_map(|(ident, type_)| { - if matches!(&type_.variant, TypeVariant::ComplexType(ci) if ci.has_complex_content(types)) { + if matches!(&type_.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::{ElementInfo, ElementMode, ElementsInfo, Ident, Type, ComplexTypeVariant, Types, TypeDescriptor} }; + 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..1ab9cec3 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::{type_::SimpleTypeVariant, Ident, Types, UnionInfo, UnionTypeInfo}; use super::{Error, TypeTransformer}; @@ -20,9 +20,9 @@ impl TypeTransformer for FlattenUnions { tracing::debug!("flatten_unions"); let idents = types - .iter() + .simple_types_iter() .filter_map(|(ident, type_)| { - if matches!(&type_.variant, TypeVariant::Union(_)) { + if matches!(&type_.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..c481daa1 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::{type_::ComplexTypeVariant, Ident, Types}, }; use super::{Error, TypeTransformer}; @@ -20,9 +20,9 @@ impl TypeTransformer for MergeChoiceCardinalities { let idents = types - .iter() + .complex_types_iter() .filter_map(|(ident, type_)| { - if matches!(&type_.variant, TypeVariant::ComplexType(ci) if ci.has_complex_choice_content(types)) { + if matches!(&type_.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..28fb3c13 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, + type_::SimpleTypeVariant, EnumerationInfo, Ident, 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() + .simple_types_iter() .filter_map(|(ident, type_)| { - if matches!(&type_.variant, TypeVariant::Union(_)) { + if matches!(&type_.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..5eb7b940 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() { + for (_, type_) in types.simple_types_iter_mut() { match &mut type_.variant { - TypeVariant::Reference(x) if x.is_single() => { + 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 (_, type_) in types.complex_types_iter_mut() { + match &mut type_.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 (_, type_) in types.complex_types_iter_mut() { + let ComplexTypeVariant::Dynamic(di) = &mut type_.variant else { continue; }; diff --git a/src/optimizer/unrestricted_base.rs b/src/optimizer/unrestricted_base.rs index 4970e5fc..807af37a 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::{ReferenceInfo, SimpleTypeVariant, Types}; use super::{Error, TypeTransformer}; @@ -38,14 +38,12 @@ impl TypeTransformer for UseUnrestrictedBaseType { let bases = crate::optimizer::BaseMap::new(types); - for (ident, type_) in types.iter_mut() { + for (ident, type_) in types.simple_types_iter_mut() { match &type_.variant { - TypeVariant::ComplexType(_) - | TypeVariant::Enumeration(_) - | TypeVariant::Union(_) => { + SimpleTypeVariant::Enumeration(_) | SimpleTypeVariant::Union(_) => { let base = bases.get_unrestricted(ident).clone(); if *ident != base { - type_.variant = TypeVariant::Reference(ReferenceInfo::new(base)); + type_.variant = SimpleTypeVariant::Reference(ReferenceInfo::new(base)); } } _ => (), diff --git a/src/types/info/complex.rs b/src/types/info/complex.rs index 4e85992a..ef1bf3bd 100644 --- a/src/types/info/complex.rs +++ b/src/types/info/complex.rs @@ -7,7 +7,8 @@ use crate::schema::xs::{ QnameListType, }; use crate::schema::{MaxOccurs, MinOccurs}; -use crate::types::{Ident, TypeEq, TypeVariant, Types}; +use crate::types::type_::ComplexTypeVariant; +use crate::types::{Ident, TypeEq, Types}; use super::{AttributesInfo, Base, ElementsInfo}; @@ -104,48 +105,46 @@ 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(_) - ) + .and_then(|ident| types.get_resolved_simple_type(ident)), + Some(_) ) } } diff --git a/src/types/mod.rs b/src/types/mod.rs index 30373760..080359bb 100644 --- a/src/types/mod.rs +++ b/src/types/mod.rs @@ -15,6 +15,8 @@ use std::ops::DerefMut; use std::sync::atomic::AtomicUsize; use std::sync::Arc; +pub use type_::{ComplexType, ComplexTypeVariant, SimpleType, SimpleTypeVariant, TypeDescriptor}; + pub use self::custom::CustomType; pub use self::helper::{VecHelper, WithIdent}; pub use self::ident::{Ident, IdentType}; @@ -25,7 +27,7 @@ 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, Type, TypeEq}; use crate::schema::{Namespace, NamespaceId}; @@ -56,6 +58,76 @@ pub struct Module { } impl Types { + 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, + }) + } + + 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, + }) + } + + 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, + }) + } + + 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, + }) + } + + 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)), + _ => None, + }) + } + + 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, type_descriptor)), + _ => None, + }) + } + + 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)), + _ => None, + }) + } + + 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, type_descriptor)), + _ => 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 +155,39 @@ impl Types { self.get_resolved(ident).map(|(_ident, ty)| ty) } - /// Get the type ident 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. #[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(ident) + .map(|(_ident, ty)| ty) + .and_then(|a| match a { + Type::ComplexType(type_descriptor) => Some(type_descriptor), + _ => None, + }) } - /// Return the [`TypeVariant`] of corresponding type for the passed identifier. - /// - /// This is a shorthand for `self.get(ident).map(|ty| &type.variant)`. - #[inline] #[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(ident) + .map(|(_ident, ty)| ty) + .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 +225,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..eb63ec3f 100644 --- a/src/types/type_.rs +++ b/src/types/type_.rs @@ -9,19 +9,117 @@ use super::{ UnionInfo, }; +pub type SimpleType = TypeDescriptor; +pub type ComplexType = TypeDescriptor; + +#[derive(Debug, Clone)] +pub enum Type { + SimpleType(SimpleType), + ComplexType(ComplexType), +} + +impl Type { + pub fn display_name(&self) -> Option<&str> { + match self { + Type::SimpleType(TypeDescriptor { display_name, .. }) + | Type::ComplexType(TypeDescriptor { display_name, .. }) => display_name.as_deref(), + } + } + pub fn display_name_mut(&mut self) -> &mut Option { + match self { + Type::SimpleType(TypeDescriptor { display_name, .. }) + | Type::ComplexType(TypeDescriptor { display_name, .. }) => display_name, + } + } + + 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) + } + } + } + + 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) + } + } + } + + pub fn simple_type_ref(&self) -> Option<&SimpleType> { + match self { + Type::SimpleType(type_descriptor) => Some(type_descriptor), + _ => None, + } + } + + pub fn complex_type_ref(&self) -> Option<&ComplexType> { + match self { + Type::ComplexType(type_descriptor) => Some(type_descriptor), + _ => None, + } + } + + 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, +} + +#[derive(Debug, Clone)] +pub enum TypeVariant { + SimpleType(S), + ComplexType(C), +} + +impl TypeVariant { + pub fn into_complex_type_variant(self) -> ComplexTypeVariant { + match self { + TypeVariant::SimpleType(variant) => ComplexTypeVariant::SimpleType(variant), + TypeVariant::ComplexType(variant) => variant, + } + } +} + +impl, C: Deref> + TypeVariant +{ + 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 +131,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 +153,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 +235,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 +298,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 +324,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 +411,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(); From b8f6008658cf4d51668dc54f08d6aa2124e91fe9 Mon Sep 17 00:00:00 2001 From: Lukas Friman Date: Wed, 23 Apr 2025 21:40:41 +0200 Subject: [PATCH 06/12] Simplified simple/complex iteration as a consequence of needing to iterate Complex Simple types. --- src/generator/misc.rs | 4 ++-- src/optimizer/empty_enums.rs | 11 +++++------ src/optimizer/empty_unions.rs | 11 +++++------ src/optimizer/flatten_complex_type.rs | 4 ++-- src/optimizer/flatten_unions.rs | 4 ++-- src/optimizer/merge_choice_cardinality.rs | 4 ++-- src/optimizer/merge_enum_unions.rs | 6 +++--- src/optimizer/resolve_typedefs.rs | 12 ++++++------ src/optimizer/unrestricted_base.rs | 24 ++++++++++++++--------- src/types/mod.rs | 24 +++++++++++------------ 10 files changed, 54 insertions(+), 50 deletions(-) diff --git a/src/generator/misc.rs b/src/generator/misc.rs index 35b81ed5..335ce80c 100644 --- a/src/generator/misc.rs +++ b/src/generator/misc.rs @@ -342,8 +342,8 @@ impl TraitInfos { pub(super) fn new(types: &Types) -> Self { let mut ret = Self(BTreeMap::new()); - for (base_ident, ty) in types.complex_types_iter() { - let ComplexTypeVariant::Dynamic(ai) = &ty.variant else { + for (base_ident, variant) in types.complex_types_iter() { + let ComplexTypeVariant::Dynamic(ai) = variant else { continue; }; diff --git a/src/optimizer/empty_enums.rs b/src/optimizer/empty_enums.rs index 6abc521f..796f53c3 100644 --- a/src/optimizer/empty_enums.rs +++ b/src/optimizer/empty_enums.rs @@ -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.simple_types_iter_mut() { - if let SimpleTypeVariant::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,12 +72,11 @@ impl TypeTransformer for RemoveEmptyEnums { fn transform(&self, types: &mut Types) -> Result<(), super::Error> { tracing::debug!("remove_empty_enums"); - for (_, type_) in types.simple_types_iter_mut() { - if let SimpleTypeVariant::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 = - SimpleTypeVariant::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 72e06ec7..3c2106de 100644 --- a/src/optimizer/empty_unions.rs +++ b/src/optimizer/empty_unions.rs @@ -36,8 +36,8 @@ impl TypeTransformer for RemoveDuplicateUnionVariants { let typedefs = crate::optimizer::TypedefMap::new(types); - for (_, type_) in types.simple_types_iter_mut() { - if let SimpleTypeVariant::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,13 +84,12 @@ impl TypeTransformer for RemoveEmptyUnions { fn transform(&self, types: &mut Types) -> Result<(), super::Error> { tracing::debug!("remove_empty_unions"); - for (_, type_) in types.simple_types_iter_mut() { - if let SimpleTypeVariant::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 = - SimpleTypeVariant::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 2263810b..231d1ced 100644 --- a/src/optimizer/flatten_complex_type.rs +++ b/src/optimizer/flatten_complex_type.rs @@ -37,8 +37,8 @@ impl TypeTransformer for FlattenComplexTypes { let idents = types .complex_types_iter() - .filter_map(|(ident, type_)| { - if matches!(&type_.variant, ComplexTypeVariant::ComplexType(ci) if ci.has_complex_content(types)) { + .filter_map(|(ident, variant)| { + if matches!(&variant, ComplexTypeVariant::ComplexType(ci) if ci.has_complex_content(types)) { Some(ident) } else { None diff --git a/src/optimizer/flatten_unions.rs b/src/optimizer/flatten_unions.rs index 1ab9cec3..f5c3557c 100644 --- a/src/optimizer/flatten_unions.rs +++ b/src/optimizer/flatten_unions.rs @@ -21,8 +21,8 @@ impl TypeTransformer for FlattenUnions { let idents = types .simple_types_iter() - .filter_map(|(ident, type_)| { - if matches!(&type_.variant, SimpleTypeVariant::Union(_)) { + .filter_map(|(ident, variant)| { + if matches!(&variant, SimpleTypeVariant::Union(_)) { Some(ident) } else { None diff --git a/src/optimizer/merge_choice_cardinality.rs b/src/optimizer/merge_choice_cardinality.rs index c481daa1..af5011dd 100644 --- a/src/optimizer/merge_choice_cardinality.rs +++ b/src/optimizer/merge_choice_cardinality.rs @@ -21,8 +21,8 @@ impl TypeTransformer for MergeChoiceCardinalities { let idents = types .complex_types_iter() - .filter_map(|(ident, type_)| { - if matches!(&type_.variant, ComplexTypeVariant::ComplexType(ci) if ci.has_complex_choice_content(types)) { + .filter_map(|(ident, variant)| { + if matches!(&variant, ComplexTypeVariant::ComplexType(ci) if ci.has_complex_choice_content(types)) { Some(ident) } else { None diff --git a/src/optimizer/merge_enum_unions.rs b/src/optimizer/merge_enum_unions.rs index 28fb3c13..83fca406 100644 --- a/src/optimizer/merge_enum_unions.rs +++ b/src/optimizer/merge_enum_unions.rs @@ -19,8 +19,8 @@ impl TypeTransformer for MergeEnumUnions { let idents = types .simple_types_iter() - .filter_map(|(ident, type_)| { - if matches!(&type_.variant, SimpleTypeVariant::Union(_)) { + .filter_map(|(ident, variant)| { + if matches!(&variant, SimpleTypeVariant::Union(_)) { Some(ident) } else { None @@ -93,7 +93,7 @@ impl MergeEnumUnions { display_name: Option<&str>, next: &mut Option, ) { - let Some(type_) = types.get_simple_type(&ident).map(|x| &x.variant) else { + let Some(type_) = types.get_simple_type(ident).map(|x| &x.variant) else { return; }; diff --git a/src/optimizer/resolve_typedefs.rs b/src/optimizer/resolve_typedefs.rs index 5eb7b940..1cf98c43 100644 --- a/src/optimizer/resolve_typedefs.rs +++ b/src/optimizer/resolve_typedefs.rs @@ -46,8 +46,8 @@ impl TypeTransformer for ResolveTypedefs { let mut replaced_references = HashMap::new(); - for (_, type_) in types.simple_types_iter_mut() { - match &mut type_.variant { + 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 @@ -75,8 +75,8 @@ impl TypeTransformer for ResolveTypedefs { } } - for (_, type_) in types.complex_types_iter_mut() { - match &mut type_.variant { + 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 @@ -113,8 +113,8 @@ impl TypeTransformer for ResolveTypedefs { } } - for (_, type_) in types.complex_types_iter_mut() { - let ComplexTypeVariant::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 807af37a..822aaea9 100644 --- a/src/optimizer/unrestricted_base.rs +++ b/src/optimizer/unrestricted_base.rs @@ -1,4 +1,4 @@ -use crate::types::{ReferenceInfo, SimpleTypeVariant, Types}; +use crate::types::{ComplexTypeVariant, ReferenceInfo, SimpleTypeVariant, Types}; use super::{Error, TypeTransformer}; @@ -38,15 +38,21 @@ impl TypeTransformer for UseUnrestrictedBaseType { let bases = crate::optimizer::BaseMap::new(types); - for (ident, type_) in types.simple_types_iter_mut() { - match &type_.variant { - SimpleTypeVariant::Enumeration(_) | SimpleTypeVariant::Union(_) => { - let base = bases.get_unrestricted(ident).clone(); - if *ident != base { - type_.variant = SimpleTypeVariant::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/mod.rs b/src/types/mod.rs index 080359bb..23e3bc96 100644 --- a/src/types/mod.rs +++ b/src/types/mod.rs @@ -92,38 +92,38 @@ impl Types { }) } - pub fn simple_types_iter( - &self, - ) -> impl Iterator)> { + 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)), + Type::SimpleType(type_descriptor) => Some((ident, &type_descriptor.variant)), + Type::ComplexType(TypeDescriptor { + variant: ComplexTypeVariant::SimpleType(simple_type), + .. + }) => Some((ident, simple_type)), _ => None, }) } pub fn simple_types_iter_mut( &mut self, - ) -> impl Iterator)> { + ) -> impl Iterator { self.types.iter_mut().filter_map(|(ident, t)| match t { - Type::SimpleType(type_descriptor) => Some((ident, type_descriptor)), + Type::SimpleType(type_descriptor) => Some((ident, &mut type_descriptor.variant)), _ => None, }) } - pub fn complex_types_iter( - &self, - ) -> impl Iterator)> { + 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)), + Type::ComplexType(type_descriptor) => Some((ident, &type_descriptor.variant)), _ => None, }) } pub fn complex_types_iter_mut( &mut self, - ) -> impl Iterator)> { + ) -> impl Iterator { self.types.iter_mut().filter_map(|(ident, t)| match t { - Type::ComplexType(type_descriptor) => Some((ident, type_descriptor)), + Type::ComplexType(type_descriptor) => Some((ident, &mut type_descriptor.variant)), _ => None, }) } From 60ff90946052bd5b597bdac842244766d966bbf9 Mon Sep 17 00:00:00 2001 From: Lukas Friman Date: Thu, 24 Apr 2025 07:06:15 +0200 Subject: [PATCH 07/12] Fixed example --- examples/update_schema.rs | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) 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", + )))), ), ]; From e6c2a09715a44cbf1c1300a725237ac145ccae10 Mon Sep 17 00:00:00 2001 From: Lukas Friman Date: Thu, 24 Apr 2025 10:29:58 +0200 Subject: [PATCH 08/12] Clippy fixes. --- src/optimizer/dynamic_to_choice.rs | 5 ++--- src/optimizer/flatten_complex_type.rs | 2 +- src/types/info/complex.rs | 10 ++++------ 3 files changed, 7 insertions(+), 10 deletions(-) diff --git a/src/optimizer/dynamic_to_choice.rs b/src/optimizer/dynamic_to_choice.rs index 03ce31e6..45aefe3f 100644 --- a/src/optimizer/dynamic_to_choice.rs +++ b/src/optimizer/dynamic_to_choice.rs @@ -66,9 +66,8 @@ impl TypeTransformer for ConvertDynamicToChoice { crate::unreachable!(); }; - let x = match variant { - ComplexTypeVariant::Dynamic(x) => x, - _ => crate::unreachable!(), + let ComplexTypeVariant::Dynamic(x) = variant else { + crate::unreachable!(); }; let mut si = GroupInfo::default(); diff --git a/src/optimizer/flatten_complex_type.rs b/src/optimizer/flatten_complex_type.rs index 231d1ced..b81d0efb 100644 --- a/src/optimizer/flatten_complex_type.rs +++ b/src/optimizer/flatten_complex_type.rs @@ -260,7 +260,7 @@ impl Default for ContextOccurs { #[cfg(test)] mod tests { use crate::{ - optimizer::{flatten_complex_type::FlattenComplexTypes, TypeTransformer}, schema::MaxOccurs, types::{ElementInfo, ElementMode, ElementsInfo, Ident, Type, ComplexTypeVariant, Types, TypeDescriptor} + optimizer::{flatten_complex_type::FlattenComplexTypes, TypeTransformer}, schema::MaxOccurs, types::{ComplexTypeVariant, ElementInfo, ElementMode, ElementsInfo, Ident, Type, TypeDescriptor, Types} }; diff --git a/src/types/info/complex.rs b/src/types/info/complex.rs index ef1bf3bd..31d520dd 100644 --- a/src/types/info/complex.rs +++ b/src/types/info/complex.rs @@ -140,12 +140,10 @@ impl ComplexInfo { /// `false` otherwise. #[must_use] pub fn has_simple_content(&self, types: &Types) -> bool { - matches!( - self.content - .as_ref() - .and_then(|ident| types.get_resolved_simple_type(ident)), - Some(_) - ) + self.content + .as_ref() + .and_then(|ident| types.get_resolved_simple_type(ident)) + .is_some() } } From 0a75b1988f7fb0fc0a48b158242a2c04672a3418 Mon Sep 17 00:00:00 2001 From: Lukas Friman Date: Fri, 25 Apr 2025 17:23:32 +0200 Subject: [PATCH 09/12] Import fixes. Fixed bug in generator just looking for complex types. --- src/generator/data.rs | 10 ++++++---- src/interpreter/builders/complex_type.rs | 3 +-- src/misc.rs | 3 +-- src/optimizer/dynamic_to_choice.rs | 4 ++-- src/optimizer/empty_enums.rs | 2 +- src/optimizer/empty_unions.rs | 2 +- src/optimizer/flatten_complex_type.rs | 2 +- src/optimizer/flatten_unions.rs | 2 +- src/optimizer/merge_choice_cardinality.rs | 2 +- src/optimizer/merge_enum_unions.rs | 2 +- src/types/info/complex.rs | 3 +-- src/types/mod.rs | 7 ++++--- 12 files changed, 21 insertions(+), 21 deletions(-) diff --git a/src/generator/data.rs b/src/generator/data.rs index 495af881..3a379516 100644 --- a/src/generator/data.rs +++ b/src/generator/data.rs @@ -8,7 +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, ComplexTypeVariant, DynamicInfo, ElementInfo, EnumerationInfo, GroupInfo, Ident, ReferenceInfo, SimpleTypeVariant, Type, TypeDescriptor, Types, UnionInfo, UnionTypeInfo, VariantInfo + TypeVariant, AnyAttributeInfo, AnyInfo, AttributeInfo, BuildInInfo, ComplexInfo, ComplexTypeVariant, DynamicInfo, ElementInfo, EnumerationInfo, GroupInfo, Ident, ReferenceInfo, SimpleTypeVariant, Type, TypeDescriptor, Types, UnionInfo, UnionTypeInfo, VariantInfo }, }; @@ -241,6 +241,7 @@ impl<'types> DynamicType<'types> { .collect::, _>>() }) .transpose()?; + println!("HERE: {:?}", info.derived_types); let derived_types = info .derived_types .iter() @@ -1293,6 +1294,7 @@ impl<'a, 'types> Request<'a, 'types> { ident: &Ident, ) -> Result { let types = self.types; + println!("A"); let ty = types .get(ident) .ok_or_else(|| Error::UnknownType(ident.clone()))?; @@ -1453,11 +1455,11 @@ fn make_derived_type_data<'types>( let s_name = ident.name.to_string(); let b_name = Literal::byte_string(s_name.as_bytes()); - let complex_ty = req + let ty = req .types - .get_complex_type(ident) + .get(ident) .ok_or_else(|| Error::UnknownType(ident.clone()))?; - let base_ident = if let ComplexTypeVariant::Dynamic(di) = &complex_ty.variant { + let base_ident = if let TypeVariant::ComplexType(ComplexTypeVariant::Dynamic(di)) = &ty.variant() { di.type_.clone() } else { None diff --git a/src/interpreter/builders/complex_type.rs b/src/interpreter/builders/complex_type.rs index 1fe0db25..41e8d030 100644 --- a/src/interpreter/builders/complex_type.rs +++ b/src/interpreter/builders/complex_type.rs @@ -10,10 +10,9 @@ use crate::schema::xs::{ ElementType, ExtensionType, Facet, GroupType, RestrictionType, SimpleContent, }; use crate::schema::{MaxOccurs, MinOccurs}; -use crate::types::type_::TypeVariant; use crate::types::{ AnyInfo, AttributeInfo, Base, ComplexType, ComplexTypeVariant, ElementInfo, ElementMode, Ident, - IdentType, Name, SimpleType, SimpleTypeVariant, Type, VecHelper, + IdentType, Name, SimpleType, SimpleTypeVariant, Type, TypeVariant, VecHelper, }; use super::super::{Error, SchemaInterpreter}; diff --git a/src/misc.rs b/src/misc.rs index d972d747..3664b723 100644 --- a/src/misc.rs +++ b/src/misc.rs @@ -6,8 +6,7 @@ use std::io::Error as IoError; use anyhow::Error as AnyError; use thiserror::Error; -use crate::types::type_::{ComplexTypeVariant, SimpleTypeVariant}; -use crate::types::{ElementMode, Ident, Type, Types}; +use crate::types::{ComplexTypeVariant, ElementMode, Ident, SimpleTypeVariant, Type, Types}; use crate::{GeneratorError, InterpreterError, OptimizerError, ParserError}; /// Trait that adds namespace information to a type. diff --git a/src/optimizer/dynamic_to_choice.rs b/src/optimizer/dynamic_to_choice.rs index 45aefe3f..bf8c3dc1 100644 --- a/src/optimizer/dynamic_to_choice.rs +++ b/src/optimizer/dynamic_to_choice.rs @@ -1,6 +1,6 @@ use crate::types::{ - type_::{ComplexTypeVariant, TypeDescriptor}, - ComplexInfo, ElementInfo, ElementMode, GroupInfo, Ident, Type, Types, VecHelper, + ComplexInfo, ComplexTypeVariant, ElementInfo, ElementMode, GroupInfo, Ident, Type, + TypeDescriptor, Types, VecHelper, }; use super::TypeTransformer; diff --git a/src/optimizer/empty_enums.rs b/src/optimizer/empty_enums.rs index 796f53c3..715071de 100644 --- a/src/optimizer/empty_enums.rs +++ b/src/optimizer/empty_enums.rs @@ -1,4 +1,4 @@ -use crate::types::{type_::SimpleTypeVariant, Name, ReferenceInfo, Types}; +use crate::types::{Name, ReferenceInfo, SimpleTypeVariant, Types}; use super::TypeTransformer; diff --git a/src/optimizer/empty_unions.rs b/src/optimizer/empty_unions.rs index 3c2106de..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::{type_::SimpleTypeVariant, ReferenceInfo, Types}; +use crate::types::{ReferenceInfo, SimpleTypeVariant, Types}; use super::TypeTransformer; diff --git a/src/optimizer/flatten_complex_type.rs b/src/optimizer/flatten_complex_type.rs index b81d0efb..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::{type_::{ComplexTypeVariant, TypeDescriptor}, ElementInfo, ElementMode, GroupInfo, Ident, Type, Types}, + types::{ComplexTypeVariant, TypeDescriptor, ElementInfo, ElementMode, GroupInfo, Ident, Type, Types}, }; use super::{Error, TypeTransformer}; diff --git a/src/optimizer/flatten_unions.rs b/src/optimizer/flatten_unions.rs index f5c3557c..a7467873 100644 --- a/src/optimizer/flatten_unions.rs +++ b/src/optimizer/flatten_unions.rs @@ -1,4 +1,4 @@ -use crate::types::{type_::SimpleTypeVariant, Ident, Types, UnionInfo, UnionTypeInfo}; +use crate::types::{Ident, SimpleTypeVariant, Types, UnionInfo, UnionTypeInfo}; use super::{Error, TypeTransformer}; diff --git a/src/optimizer/merge_choice_cardinality.rs b/src/optimizer/merge_choice_cardinality.rs index af5011dd..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::{type_::ComplexTypeVariant, Ident, Types}, + types::{ComplexTypeVariant, Ident, Types}, }; use super::{Error, TypeTransformer}; diff --git a/src/optimizer/merge_enum_unions.rs b/src/optimizer/merge_enum_unions.rs index 83fca406..97112dcc 100644 --- a/src/optimizer/merge_enum_unions.rs +++ b/src/optimizer/merge_enum_unions.rs @@ -1,5 +1,5 @@ use crate::types::{ - type_::SimpleTypeVariant, EnumerationInfo, Ident, Types, UnionInfo, UnionTypeInfo, VariantInfo, + EnumerationInfo, Ident, SimpleTypeVariant, Types, UnionInfo, UnionTypeInfo, VariantInfo, VecHelper, }; diff --git a/src/types/info/complex.rs b/src/types/info/complex.rs index 31d520dd..df0a8792 100644 --- a/src/types/info/complex.rs +++ b/src/types/info/complex.rs @@ -7,8 +7,7 @@ use crate::schema::xs::{ QnameListType, }; use crate::schema::{MaxOccurs, MinOccurs}; -use crate::types::type_::ComplexTypeVariant; -use crate::types::{Ident, TypeEq, Types}; +use crate::types::{ComplexTypeVariant, Ident, TypeEq, Types}; use super::{AttributesInfo, Base, ElementsInfo}; diff --git a/src/types/mod.rs b/src/types/mod.rs index 23e3bc96..b82a7356 100644 --- a/src/types/mod.rs +++ b/src/types/mod.rs @@ -15,8 +15,6 @@ use std::ops::DerefMut; use std::sync::atomic::AtomicUsize; use std::sync::Arc; -pub use type_::{ComplexType, ComplexTypeVariant, SimpleType, SimpleTypeVariant, TypeDescriptor}; - pub use self::custom::CustomType; pub use self::helper::{VecHelper, WithIdent}; pub use self::ident::{Ident, IdentType}; @@ -27,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}; +pub use self::type_::{ + BuildInInfo, ComplexType, ComplexTypeVariant, SimpleType, SimpleTypeVariant, Type, + TypeDescriptor, TypeEq, TypeVariant, +}; use crate::schema::{Namespace, NamespaceId}; From 14f3a0020fc443d6490ab623d39b617f4c1206a0 Mon Sep 17 00:00:00 2001 From: Lukas Friman Date: Wed, 7 May 2025 20:52:09 +0200 Subject: [PATCH 10/12] Changes in response to PR review. --- src/interpreter/builders/attribute_type.rs | 17 +++++------------ src/interpreter/builders/complex_type.rs | 6 +++--- src/interpreter/builders/element.rs | 3 +-- src/interpreter/builders/simple_type.rs | 8 ++++---- src/interpreter/name_builder.rs | 2 +- src/interpreter/schema.rs | 19 +++++++++---------- src/interpreter/state.rs | 2 +- 7 files changed, 24 insertions(+), 33 deletions(-) diff --git a/src/interpreter/builders/attribute_type.rs b/src/interpreter/builders/attribute_type.rs index fa80fd9a..c2fe4dda 100644 --- a/src/interpreter/builders/attribute_type.rs +++ b/src/interpreter/builders/attribute_type.rs @@ -18,9 +18,6 @@ pub(crate) struct AttributeTypeBuilder<'a, 'schema, 'state> { /// Type variant that is constructed by the builder variant: Option, - /// `true` if `type_` is fixed and can not be changed anymore - fixed: bool, - owner: &'a mut SchemaInterpreter<'schema, 'state>, } @@ -28,9 +25,8 @@ pub(crate) struct AttributeTypeBuilder<'a, 'schema, 'state> { /// Initialize the type of a `$builder` to any type `$variant`. macro_rules! init_any { - ($builder:expr, $variant:ident, $value:expr, $fixed:expr) => {{ + ($builder:expr, $variant:ident, $value:expr) => {{ $builder.variant = Some(TypeVariant::$variant($value)); - $builder.fixed = $fixed; let TypeVariant::$variant(ret) = $builder.variant.as_mut().unwrap() else { crate::unreachable!(); @@ -47,10 +43,9 @@ macro_rules! get_or_init_any { }; ($builder:expr, $variant:ident, $default:expr) => { match &mut $builder.variant { - None => init_any!($builder, $variant, $default, true), + None => init_any!($builder, $variant, $default), 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), + _ => init_any!($builder, $variant, $default), } }; } @@ -62,13 +57,11 @@ impl<'a, 'schema, 'state> AttributeTypeBuilder<'a, 'schema, 'state> { Self { type_: None, variant: None, - fixed: false, owner, } } pub(crate) fn finish(self) -> Result { - println!("AttributeTypeBuilder::finish"); self.type_ .or_else(|| self.variant.map(Type::new)) .ok_or(Error::NoType) @@ -78,7 +71,7 @@ impl<'a, 'schema, 'state> AttributeTypeBuilder<'a, 'schema, 'state> { pub(crate) 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); + init_any!(self, Reference, ReferenceInfo::new(type_)); } else if let Some(x) = &ty.simple_type { let mut builder = SimpleTypeBuilder::new(self.owner); builder.apply_simple_type(x)?; @@ -136,7 +129,7 @@ impl<'a, 'schema, 'state> AttributeTypeBuilder<'a, 'schema, 'state> { .state .name_builder() .or(name) - .auto_extend2(true, true, self.state) + .auto_extend(true, true, self.state) .finish(); let ns = self.state.current_ns(); diff --git a/src/interpreter/builders/complex_type.rs b/src/interpreter/builders/complex_type.rs index 1ad40ed3..a1556a7e 100644 --- a/src/interpreter/builders/complex_type.rs +++ b/src/interpreter/builders/complex_type.rs @@ -392,7 +392,7 @@ impl<'a, 'schema, 'state> ComplexTypeBuilder<'a, 'schema, 'state> { .state .name_builder() .extend(true, ty.name.clone()) - .auto_extend2(true, false, self.state); + .auto_extend(true, false, self.state); let type_name = if type_name.has_extension() { type_name.with_id(false) } else { @@ -517,7 +517,7 @@ impl<'a, 'schema, 'state> ComplexTypeBuilder<'a, 'schema, 'state> { .state .name_builder() .or(name) - .auto_extend2(true, true, self.state) + .auto_extend(true, true, self.state) .finish(); let ns = self.state.current_ns(); @@ -845,7 +845,7 @@ impl<'a, 'schema, 'state> ComplexTypeBuilder<'a, 'schema, 'state> { .remove_suffix("Content"); let field_name = name.clone().shared_name("Content").finish(); let type_name = name - .auto_extend2(false, true, self.state) + .auto_extend(false, true, self.state) .remove_suffix("Type") .remove_suffix("Content") .shared_name("Content") diff --git a/src/interpreter/builders/element.rs b/src/interpreter/builders/element.rs index bf799e14..ddefb49b 100644 --- a/src/interpreter/builders/element.rs +++ b/src/interpreter/builders/element.rs @@ -69,7 +69,6 @@ impl<'a, 'schema, 'state> ElementBuilder<'a, 'schema, 'state> { } pub(crate) fn finish(self) -> Result { - println!("ElementBuilder::finish"); let variant = self.variant.ok_or(Error::NoType)?; Ok(Type::new(variant)) @@ -198,7 +197,7 @@ impl<'a, 'schema, 'state> ElementBuilder<'a, 'schema, 'state> { .state .name_builder() .extend(true, ty.name.clone()) - .auto_extend2(true, false, self.state); + .auto_extend(true, false, self.state); let type_name = if type_name.has_extension() { type_name.with_id(false) } else { diff --git a/src/interpreter/builders/simple_type.rs b/src/interpreter/builders/simple_type.rs index 6a931404..728e365a 100644 --- a/src/interpreter/builders/simple_type.rs +++ b/src/interpreter/builders/simple_type.rs @@ -104,7 +104,7 @@ impl<'a, 'schema, 'state> SimpleTypeBuilder<'a, 'schema, 'state> { .map(|base| { let base = self.parse_qname(base)?; - self.copy_base_type(&base, UpdateMode::Restriction)?; + self.copy_base_type(&base)?; Ok(base) }) @@ -174,7 +174,7 @@ impl<'a, 'schema, 'state> SimpleTypeBuilder<'a, 'schema, 'state> { .state .name_builder() .or(&x.name) - .auto_extend2(false, true, self.owner.state) + .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_)); @@ -223,7 +223,7 @@ impl<'a, 'schema, 'state> SimpleTypeBuilder<'a, 'schema, 'state> { } } - fn copy_base_type(&mut self, base: &Ident, _mode: UpdateMode) -> Result<(), Error> { + fn copy_base_type(&mut self, base: &Ident) -> Result<(), Error> { let base = { self.fixed = false; @@ -235,7 +235,7 @@ impl<'a, 'schema, 'state> SimpleTypeBuilder<'a, 'schema, 'state> { let mut base = base.clone(); if let TypeVariant::Enumeration(ei) = &mut base { - ei.variants.clear() + ei.variants.clear(); } self.variant = Some(base); diff --git a/src/interpreter/name_builder.rs b/src/interpreter/name_builder.rs index 9c3cb845..b6326c7a 100644 --- a/src/interpreter/name_builder.rs +++ b/src/interpreter/name_builder.rs @@ -3,7 +3,7 @@ use crate::types::NameBuilder; use super::state::State; impl NameBuilder { - pub(super) fn auto_extend2( + pub(super) fn auto_extend( self, stop_at_group: bool, replace: bool, diff --git a/src/interpreter/schema.rs b/src/interpreter/schema.rs index cdf7d3e1..47702997 100644 --- a/src/interpreter/schema.rs +++ b/src/interpreter/schema.rs @@ -1,4 +1,3 @@ -use std::ops::DerefMut; use std::str::from_utf8; use tracing::instrument; @@ -174,8 +173,8 @@ impl SchemaInterpreter<'_, '_> { type_: IdentType::Element, }; - self.create_type_new(ident.clone(), move |mut owner| { - let mut builder = builders::ElementBuilder::new(owner.deref_mut()); + self.create_type(ident.clone(), move |owner| { + let mut builder = builders::ElementBuilder::new(owner); builder.apply_element(ty)?; let type_ = builder.finish()?; @@ -196,8 +195,8 @@ impl SchemaInterpreter<'_, '_> { type_: IdentType::Attribute, }; - self.create_type_new(ident.clone(), move |mut owner| { - let mut builder = builders::AttributeTypeBuilder::new(owner.deref_mut()); + self.create_type(ident.clone(), move |owner| { + let mut builder = builders::AttributeTypeBuilder::new(owner); builder.apply_attribute(ty)?; let type_ = builder.finish()?; @@ -219,8 +218,8 @@ impl SchemaInterpreter<'_, '_> { type_: ident_type.unwrap_or(IdentType::Type), }; - self.create_type_new(ident.clone(), move |mut owner| { - let mut builder = builders::SimpleTypeBuilder::new(owner.deref_mut()); + self.create_type(ident.clone(), move |owner| { + let mut builder = builders::SimpleTypeBuilder::new(owner); builder.apply_simple_type(ty)?; let type_ = builder.finish()?; @@ -242,8 +241,8 @@ impl SchemaInterpreter<'_, '_> { type_: ident_type.unwrap_or(IdentType::Type), }; - self.create_type_new(ident.clone(), move |mut owner| { - let mut builder = builders::ComplexTypeBuilder::new(owner.deref_mut()); + self.create_type(ident.clone(), move |owner| { + let mut builder = builders::ComplexTypeBuilder::new(owner); builder.apply_complex_type(ty)?; let type_ = builder.finish()?; @@ -251,7 +250,7 @@ impl SchemaInterpreter<'_, '_> { }) } - pub(super) fn create_type_new(&mut self, ident: Ident, f: F) -> Result + pub(super) fn create_type(&mut self, ident: Ident, f: F) -> Result where F: FnOnce(&mut SchemaInterpreter<'_, '_>) -> Result, { diff --git a/src/interpreter/state.rs b/src/interpreter/state.rs index 90b9a667..2cff2ddc 100644 --- a/src/interpreter/state.rs +++ b/src/interpreter/state.rs @@ -52,7 +52,7 @@ impl<'a> State<'a> { pub(super) fn make_content_name(&mut self) -> Name { self.name_builder() - .auto_extend2(false, true, self) + .auto_extend(false, true, self) .remove_suffix("Type") .remove_suffix("Content") .shared_name("Content") From 36ecde9d1f47258debcb14a4306cddbb0085f0d6 Mon Sep 17 00:00:00 2001 From: Lukas Friman Date: Fri, 9 May 2025 13:54:39 +0200 Subject: [PATCH 11/12] More PR fixes. --- src/interpreter/builders/attribute_type.rs | 55 ++++---- src/interpreter/builders/complex_type.rs | 140 +++++++++++---------- src/interpreter/builders/element.rs | 112 +++-------------- src/interpreter/builders/simple_type.rs | 101 +++++++++------ 4 files changed, 170 insertions(+), 238 deletions(-) diff --git a/src/interpreter/builders/attribute_type.rs b/src/interpreter/builders/attribute_type.rs index c2fe4dda..919a301f 100644 --- a/src/interpreter/builders/attribute_type.rs +++ b/src/interpreter/builders/attribute_type.rs @@ -5,7 +5,7 @@ use tracing::instrument; use super::Update; use crate::schema::xs::AttributeType; use crate::types::{ - AttributeInfo, Ident, IdentType, Name, ReferenceInfo, Type, TypeVariant, VecHelper, + AttributeInfo, ComplexInfo, Ident, IdentType, Name, ReferenceInfo, Type, TypeVariant, VecHelper, }; use super::super::{Error, SchemaInterpreter}; @@ -21,35 +21,6 @@ pub(crate) struct AttributeTypeBuilder<'a, 'schema, 'state> { owner: &'a mut SchemaInterpreter<'schema, 'state>, } -/* any type */ - -/// Initialize the type of a `$builder` to any type `$variant`. -macro_rules! init_any { - ($builder:expr, $variant:ident, $value:expr) => {{ - $builder.variant = Some(TypeVariant::$variant($value)); - - 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), - Some(TypeVariant::$variant(ret)) => ret, - _ => init_any!($builder, $variant, $default), - } - }; -} - /* TypeBuilder */ impl<'a, 'schema, 'state> AttributeTypeBuilder<'a, 'schema, 'state> { @@ -67,11 +38,27 @@ impl<'a, 'schema, 'state> AttributeTypeBuilder<'a, 'schema, 'state> { .ok_or(Error::NoType) } + fn get_or_init_complex(&mut self) -> &mut ComplexInfo { + match &mut self.variant { + Some(TypeVariant::ComplexType(ci)) => ci, + a @ None => { + *a = Some(TypeVariant::ComplexType(Default::default())); + + match a { + Some(TypeVariant::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_)?; - init_any!(self, Reference, ReferenceInfo::new(type_)); + + self.variant = Some(TypeVariant::Reference(ReferenceInfo::new(type_))); } else if let Some(x) = &ty.simple_type { let mut builder = SimpleTypeBuilder::new(self.owner); builder.apply_simple_type(x)?; @@ -96,7 +83,7 @@ impl<'a, 'schema, 'state> AttributeTypeBuilder<'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); @@ -112,7 +99,7 @@ impl<'a, 'schema, 'state> AttributeTypeBuilder<'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); @@ -141,7 +128,7 @@ impl<'a, 'schema, 'state> AttributeTypeBuilder<'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)) diff --git a/src/interpreter/builders/complex_type.rs b/src/interpreter/builders/complex_type.rs index a1556a7e..2e083793 100644 --- a/src/interpreter/builders/complex_type.rs +++ b/src/interpreter/builders/complex_type.rs @@ -11,8 +11,8 @@ use crate::schema::xs::{ }; use crate::schema::{MaxOccurs, MinOccurs}; use crate::types::{ - AnyInfo, AttributeInfo, Base, ElementInfo, ElementMode, Ident, IdentType, Name, Type, - TypeVariant, VecHelper, + AnyInfo, AttributeInfo, Base, ComplexInfo, ElementInfo, ElementMode, GroupInfo, Ident, + IdentType, Name, Type, TypeVariant, VecHelper, }; use super::super::{Error, SchemaInterpreter}; @@ -57,52 +57,6 @@ enum ComplexContentType { Sequence, } -/* any type */ - -/// Initialize the type of a `$builder` to any type `$variant`. -macro_rules! init_any { - ($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> ComplexTypeBuilder<'a, 'schema, 'state> { @@ -123,19 +77,64 @@ impl<'a, 'schema, 'state> ComplexTypeBuilder<'a, 'schema, 'state> { .ok_or(Error::NoType) } + fn get_or_init_complex(&mut self) -> &mut ComplexInfo { + match &mut self.variant { + Some(TypeVariant::ComplexType(ci)) => ci, + a if !self.fixed | a.is_none() => { + *a = Some(TypeVariant::ComplexType(Default::default())); + self.fixed = true; + + match a { + Some(TypeVariant::ComplexType(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" + ), + } + } + + fn get_complex(&mut self) -> &mut ComplexInfo { + match &mut self.variant { + Some(TypeVariant::ComplexType(ci)) => ci, + a => unreachable!("Expected the type to be a complex type, but it is {:?}", a), + } + } + + fn get_or_init_sequence(&mut self) -> &mut GroupInfo { + match &mut self.variant { + Some(TypeVariant::All(si) | TypeVariant::Choice(si) | TypeVariant::Sequence(si)) => si, + a if !self.fixed | a.is_none() => { + *a = Some(TypeVariant::Sequence(Default::default())); + self.fixed = true; + + match a { + Some(TypeVariant::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" + ), + } + } + #[instrument(err, level = "trace", skip(self))] pub(crate) fn apply_complex_type(&mut self, ty: &ComplexBaseType) -> Result<(), Error> { use crate::schema::xs::ComplexBaseTypeContent as C; 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)?; } @@ -174,7 +173,7 @@ impl<'a, 'schema, 'state> ComplexTypeBuilder<'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 { @@ -230,7 +229,7 @@ impl<'a, 'schema, 'state> ComplexTypeBuilder<'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(()) @@ -243,7 +242,7 @@ impl<'a, 'schema, 'state> ComplexTypeBuilder<'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(()) @@ -376,7 +375,7 @@ impl<'a, 'schema, 'state> ComplexTypeBuilder<'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) }); @@ -403,7 +402,7 @@ impl<'a, 'schema, 'state> ComplexTypeBuilder<'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) }); @@ -484,7 +483,7 @@ impl<'a, 'schema, 'state> ComplexTypeBuilder<'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); @@ -500,7 +499,7 @@ impl<'a, 'schema, 'state> ComplexTypeBuilder<'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); @@ -529,7 +528,7 @@ impl<'a, 'schema, 'state> ComplexTypeBuilder<'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)) @@ -544,7 +543,7 @@ impl<'a, 'schema, 'state> ComplexTypeBuilder<'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(()) @@ -552,7 +551,7 @@ impl<'a, 'schema, 'state> ComplexTypeBuilder<'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(()) @@ -633,7 +632,7 @@ impl<'a, 'schema, 'state> ComplexTypeBuilder<'a, 'schema, 'state> { match (simple_base_ident, self.content_mode) { (Some(base_ident), ContentMode::Simple) => { - let ci = get_or_init_any!(self, ComplexType); + let ci = self.get_or_init_complex(); ci.content.get_or_insert(base_ident); } (None, ContentMode::Simple | ContentMode::Complex) => { @@ -653,13 +652,17 @@ impl<'a, 'schema, 'state> ComplexTypeBuilder<'a, 'schema, 'state> { { match self.content_mode { ContentMode::Simple => { - let ci = get_or_init_any!(self, ComplexType); + 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 + ); + }; - let Some(mut 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(); @@ -668,6 +671,7 @@ impl<'a, 'schema, 'state> ComplexTypeBuilder<'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()); } @@ -823,7 +827,7 @@ impl<'a, 'schema, 'state> ComplexTypeBuilder<'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); diff --git a/src/interpreter/builders/element.rs b/src/interpreter/builders/element.rs index ddefb49b..5318ca19 100644 --- a/src/interpreter/builders/element.rs +++ b/src/interpreter/builders/element.rs @@ -2,13 +2,9 @@ use std::ops::{Deref, DerefMut}; use tracing::instrument; -use super::Update; use crate::schema::xs::{ElementSubstitutionGroupType, ElementType}; use crate::schema::Namespace; -use crate::types::{ - DynamicInfo, ElementInfo, ElementMode, Ident, IdentType, ReferenceInfo, Type, TypeVariant, - VecHelper, -}; +use crate::types::{DynamicInfo, Ident, IdentType, ReferenceInfo, Type, TypeVariant}; use super::super::{Error, SchemaInterpreter}; @@ -17,53 +13,22 @@ pub(crate) struct ElementBuilder<'a, 'schema, 'state> { /// Type variant that is constructed by the builder variant: Option, - /// `true` if `type_` is fixed and can not be changed anymore - fixed: bool, - owner: &'a mut SchemaInterpreter<'schema, 'state>, } -/* 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 - }}; -} +/* TypeBuilder */ -/// 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), - } - }; +impl ElementBuilder<'_, '_, '_> { + fn init_any(&mut self, variant: TypeVariant) -> &mut TypeVariant { + self.variant = Some(variant); + self.variant.as_mut().unwrap() + } } -/* TypeBuilder */ - impl<'a, 'schema, 'state> ElementBuilder<'a, 'schema, 'state> { pub(crate) fn new(owner: &'a mut SchemaInterpreter<'schema, 'state>) -> Self { Self { variant: None, - fixed: false, owner, } } @@ -81,7 +46,7 @@ impl<'a, 'schema, 'state> ElementBuilder<'a, 'schema, 'state> { if let Some(type_) = &ty.type_ { let type_ = self.parse_qname(type_)?; - init_any!(self, Reference, ReferenceInfo::new(type_), true); + self.init_any(TypeVariant::Reference(ReferenceInfo::new(type_))); } else if !ty.content.is_empty() { let ident = self .state @@ -120,7 +85,7 @@ impl<'a, 'schema, 'state> ElementBuilder<'a, 'schema, 'state> { } if let Some(type_) = type_ { - init_any!(self, Reference, ReferenceInfo::new(type_), true); + self.init_any(TypeVariant::Reference(ReferenceInfo::new(type_))); } } else { let xs = self @@ -129,7 +94,7 @@ impl<'a, 'schema, 'state> ElementBuilder<'a, 'schema, 'state> { .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); + self.init_any(TypeVariant::Reference(ReferenceInfo::new(ident))); } if ty.abstract_ { @@ -139,7 +104,10 @@ impl<'a, 'schema, 'state> ElementBuilder<'a, 'schema, 'state> { e => crate::unreachable!("Unexpected type: {:?}", e), }; - let ai = init_any!(self, Dynamic); + let TypeVariant::Dynamic(ai) = self.init_any(TypeVariant::Dynamic(Default::default())) + else { + crate::unreachable!(); + }; ai.type_ = type_; } @@ -167,58 +135,6 @@ impl<'a, 'schema, 'state> ElementBuilder<'a, 'schema, 'state> { Ok(()) } - #[instrument(err, level = "trace", skip(self))] - fn apply_element_ref(&mut self, ty: &ElementType) -> Result<(), Error> { - match ty { - ElementType { - ref_: Some(ref_), - name, - .. - } => { - let type_ = self.parse_qname(ref_)?.with_type(IdentType::Element); - let name = self.state.name_builder().or(name).or(&type_.name).finish(); - let ident = Ident::new(name) - .with_ns(type_.ns) - .with_type(IdentType::Element); - - let ci = get_or_init_type!(self, Sequence); - let element = ci.elements.find_or_insert(ident, |ident| { - ElementInfo::new(ident, type_, ElementMode::Element) - }); - crate::assert_eq!(element.element_mode, ElementMode::Element); - element.update(ty); - } - ty => { - let field_name = self.state.name_builder().or(&ty.name).finish(); - let field_ident = Ident::new(field_name) - .with_ns(self.state.current_ns()) - .with_type(IdentType::Element); - let type_name = self - .state - .name_builder() - .extend(true, ty.name.clone()) - .auto_extend(true, false, self.state); - let type_name = if type_name.has_extension() { - type_name.with_id(false) - } else { - type_name.shared_name("Temp") - }; - let type_name = type_name.finish(); - - 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 element = ci.elements.find_or_insert(field_ident, |ident| { - ElementInfo::new(ident, type_, ElementMode::Element) - }); - crate::assert_eq!(element.element_mode, ElementMode::Element); - element.update(ty); - } - } - - Ok(()) - } fn walk_substitution_groups( &mut self, diff --git a/src/interpreter/builders/simple_type.rs b/src/interpreter/builders/simple_type.rs index 728e365a..5fe36934 100644 --- a/src/interpreter/builders/simple_type.rs +++ b/src/interpreter/builders/simple_type.rs @@ -6,8 +6,8 @@ use tracing::instrument; use crate::schema::xs::{Facet, FacetType, List, Restriction, SimpleBaseType, Union, Use}; use crate::schema::MaxOccurs; use crate::types::{ - Base, Ident, IdentType, Name, ReferenceInfo, Type, TypeVariant, UnionTypeInfo, VariantInfo, - VecHelper, + Base, EnumerationInfo, Ident, IdentType, Name, ReferenceInfo, Type, TypeVariant, UnionInfo, + UnionTypeInfo, VariantInfo, VecHelper, }; use super::super::{Error, SchemaInterpreter}; @@ -32,35 +32,6 @@ enum UpdateMode { Restriction, } -/// Initialize the type of a `$builder` to any type `$variant`. -macro_rules! init_any { - ($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), - } - }; -} - /* TypeBuilder */ impl<'a, 'schema, 'state> SimpleTypeBuilder<'a, 'schema, 'state> { @@ -78,6 +49,58 @@ impl<'a, 'schema, 'state> SimpleTypeBuilder<'a, 'schema, 'state> { Ok(Type::new(variant)) } + fn get_or_init_enumeration( + variant: &mut Option, + fixed: bool, + ) -> &mut EnumerationInfo { + match variant { + Some(TypeVariant::Enumeration(ei)) => ei, + a if !fixed || a.is_none() => { + *a = Some(TypeVariant::Enumeration(Default::default())); + match a { + Some(TypeVariant::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(TypeVariant::Union(ei)) => ei, + a if !fixed || a.is_none() => { + *a = Some(TypeVariant::Union(Default::default())); + match a { + Some(TypeVariant::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(TypeVariant::Reference(ei)) => ei, + a if !fixed || a.is_none() => { + *a = Some(TypeVariant::Reference(ei)); + match a { + Some(TypeVariant::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; @@ -148,7 +171,7 @@ impl<'a, 'schema, 'state> SimpleTypeBuilder<'a, 'schema, 'state> { .with_ns(self.state.current_ns()) .with_type(IdentType::Enumeration); - let ei = get_or_init_any!(self, 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; @@ -157,7 +180,7 @@ impl<'a, 'schema, 'state> SimpleTypeBuilder<'a, 'schema, 'state> { #[instrument(err, level = "trace", skip(self))] pub fn apply_union(&mut self, ty: &Union) -> Result<(), Error> { - let ui = get_or_init_any!(self, Union); + let ui = Self::get_or_init_union(&mut self.variant, self.fixed); if let Some(types) = &ty.member_types { for type_ in &types.0 { @@ -212,7 +235,11 @@ impl<'a, 'schema, 'state> SimpleTypeBuilder<'a, 'schema, 'state> { } if let Some(type_) = type_ { - let ti = get_or_init_any!(self, Reference, ReferenceInfo::new(type_.clone())); + 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; @@ -224,11 +251,9 @@ impl<'a, 'schema, 'state> SimpleTypeBuilder<'a, 'schema, 'state> { } fn copy_base_type(&mut self, base: &Ident) -> Result<(), Error> { - let base = { - self.fixed = false; + self.fixed = false; - self.owner.get_simple_type_variant(base)? - }; + let base = self.owner.get_simple_type_variant(base)?; tracing::debug!("{base:#?}"); From ae0974660be1c6da4060db61be97e6567f947913 Mon Sep 17 00:00:00 2001 From: Lukas Friman Date: Sat, 10 May 2025 12:38:33 +0200 Subject: [PATCH 12/12] Remove debug prints --- src/generator/data.rs | 6 +++--- src/interpreter/schema.rs | 4 +--- 2 files changed, 4 insertions(+), 6 deletions(-) diff --git a/src/generator/data.rs b/src/generator/data.rs index b05c4273..b255a039 100644 --- a/src/generator/data.rs +++ b/src/generator/data.rs @@ -241,8 +241,8 @@ impl<'types> DynamicType<'types> { .collect::, _>>() }) .transpose()?; - println!("HERE: {:?}", info.derived_types); - let derived_types = info + + let derived_types = info .derived_types .iter() .map(|ident| make_derived_type_data(&mut req, ident)) @@ -1294,7 +1294,7 @@ impl<'a, 'types> Request<'a, 'types> { ident: &Ident, ) -> Result { let types = self.types; - println!("A"); + let ty = types .get(ident) .ok_or_else(|| Error::UnknownType(ident.clone()))?; diff --git a/src/interpreter/schema.rs b/src/interpreter/schema.rs index 4ecd7fdb..87b44ab4 100644 --- a/src/interpreter/schema.rs +++ b/src/interpreter/schema.rs @@ -100,14 +100,12 @@ impl SchemaInterpreter<'_, '_> { &mut self, ident: &Ident, ) -> Result<&mut SimpleTypeVariant, Error> { - println!("get_simple_type_variant: {ident}"); if !self.state.types.contains_key(ident) { let ty = self .find_simple_type(ident.clone()) .ok_or_else(|| Error::UnknownType(ident.clone()))?; - println!("get_simple_type_variant type: {ty:#?}"); + let new_ident = self.create_simple_type(ident.ns, None, None, ty)?; - println!("get_simple_type_variant new_ident: {new_ident}"); crate::assert_eq!(ident, &new_ident); }