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