xsd_parser/pipeline/optimizer/
mod.rs

1//! Type-level optimization utilities for reducing schema complexity.
2//!
3//! This module defines the [`Optimizer`] and supporting logic for transforming
4//! a [`MetaTypes`] structure into a simpler, cleaner, and smaller form.
5//!
6//! Optimizations include:
7//! - Flattening nested complex types
8//! - Removing unused or duplicate unions/enums
9//! - Resolving typedef chains
10//! - Normalizing choice cardinalities
11//! - Simplifying unrestricted base types
12//!
13//! These transformations are especially useful before code generation, to avoid
14//! verbose or redundant Rust output and ensure efficient, idiomatic structures.
15
16mod dynamic_to_choice;
17mod empty_enums;
18mod empty_unions;
19mod flatten_complex_type;
20mod flatten_unions;
21mod merge_choice_cardinality;
22mod merge_enum_unions;
23mod misc;
24mod remove_duplicates;
25mod replace_xs_any_type_with_any_element;
26mod resolve_typedefs;
27mod simplify_mixed_types;
28mod unrestricted_base;
29
30use thiserror::Error;
31
32use crate::models::{meta::MetaTypes, Ident};
33
34use self::misc::{BaseMap, TypedefMap};
35
36pub use self::unrestricted_base::UnrestrictedBaseFlags;
37
38/// Optimizes a [`MetaTypes`] structure by reducing redundant or verbose type definitions.
39///
40/// The [`Optimizer`] performs various semantic transformations on a type graph,
41/// such as flattening unions, removing empty enums, simplifying typedef chains,
42/// and reducing nested complex structures.
43///
44/// It is typically used after schema interpretation and before code generation,
45/// to ensure that only necessary and well-structured types are preserved in the final output.
46///
47/// Optimization is performed lazily; the resulting [`MetaTypes`] can be retrieved
48/// using [`finish`](Self::finish).
49#[must_use]
50#[derive(Debug)]
51pub struct Optimizer {
52    types: MetaTypes,
53    bases: Option<BaseMap>,
54    typedefs: Option<TypedefMap>,
55}
56
57/// Error that is raised by the [`Optimizer`].
58#[derive(Error, Debug)]
59pub enum Error {
60    /// Unknown type identifier.
61    ///
62    /// Is raised if a specific identifier could not be resolved to it's
63    /// corresponding type information.
64    #[error("Unknown type identifier: {0}!")]
65    UnknownType(Ident),
66
67    /// The type is not a union type.
68    ///
69    /// Is raised if a type is expected to be a union, but it is not.
70    #[error("The type is not a union type: {0}!")]
71    ExpectedUnion(Ident),
72
73    /// The type is not a complex choice type.
74    ///
75    /// Is raised if a type is expected to be a complex choice, but it is not.
76    #[error("The type is not a complex choice type: {0}!")]
77    ExpectedComplexChoice(Ident),
78
79    /// The type is not a complex type.
80    ///
81    /// Is raised if a type is expected to be a complex type, but it is not.
82    #[error("The type is not a complex type: {0}!")]
83    ExpectedComplexType(Ident),
84
85    /// The complex type is missing a content type.
86    ///
87    /// Is raised if the content type of a complex type could not be resolved.
88    #[error("Complex type {0} is missing a content type!")]
89    MissingContentType(Ident),
90
91    /// The complex type is expected to have a choice content.
92    ///
93    /// Is raised if the content type of a complex type it not a choice.
94    #[error("Complex type {0} is expected to have a choice content!")]
95    ExpectedChoiceContent(Ident),
96
97    /// The complex type is expected to have content with [`MaxOccurs::Unbounded`](crate::models::schema::MaxOccurs::Unbounded).
98    ///
99    /// Is raised if the content of a complex type does nor have unbounded occurrence.
100    #[error("Complex type {0} is expected to have content with unbound occurrence!")]
101    ExpectedUnboundContent(Ident),
102
103    /// The complex type has an unexpected content type.
104    ///
105    /// Is raised if the content type of a complex type does not match the expectations.
106    #[error("Complex type {0} has an unexpected content type!")]
107    UnexpectedContentType(Ident),
108
109    /// The complex type contains an unexpected element in it's content type.
110    ///
111    /// Is raised if any element of the content of a complex type does not match the
112    /// expectations.
113    #[error("Complex type {0} contains an unexpected element in it's content type!")]
114    UnexpectedElementInContent(Ident),
115
116    /// Custom Error
117    #[error("{0}")]
118    Custom(String),
119}
120
121macro_rules! get_bases {
122    ($this:expr) => {{
123        if $this.bases.is_none() {
124            $this.bases = Some(crate::pipeline::optimizer::BaseMap::new(&$this.types));
125        }
126
127        $this.bases.as_ref().unwrap()
128    }};
129}
130
131macro_rules! get_typedefs {
132    ($this:expr) => {{
133        if $this.typedefs.is_none() {
134            $this.typedefs = Some(crate::pipeline::optimizer::TypedefMap::new(&$this.types));
135        }
136
137        $this.typedefs.as_ref().unwrap()
138    }};
139}
140
141pub(super) use get_bases;
142pub(super) use get_typedefs;
143
144impl Optimizer {
145    /// Create a new [`Optimizer`] instance from the passed `types`.
146    pub fn new(types: MetaTypes) -> Self {
147        Self {
148            types,
149            bases: None,
150            typedefs: None,
151        }
152    }
153
154    /// Finish the optimization and return the resulting [`MetaTypes`].
155    #[must_use]
156    pub fn finish(self) -> MetaTypes {
157        self.types
158    }
159}