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}