xsd_parser/optimizer/
resolve_typedefs.rs

1use std::collections::HashMap;
2
3use crate::types::{Base, TypeVariant};
4
5use super::{get_typedefs, Optimizer};
6
7impl Optimizer {
8    /// This will resolve all simple type definitions and use the target type
9    /// directly.
10    ///
11    /// # Examples
12    ///
13    /// Consider the following XML schema.
14    /// ```xml
15    #[doc = include_str!("../../tests/optimizer/complex_flatten.xsd")]
16    /// ```
17    ///
18    /// Without this optimization this will result in the following code:
19    /// ```rust
20    #[doc = include_str!("../../tests/optimizer/expected0/resolve_typedefs.rs")]
21    /// ```
22    ///
23    /// With this optimization the following code is generated:
24    /// ```rust
25    #[doc = include_str!("../../tests/optimizer/expected1/resolve_typedefs.rs")]
26    /// ```
27    pub fn resolve_typedefs(mut self) -> Self {
28        tracing::debug!("resolve_typedefs");
29
30        let typedefs = get_typedefs!(self);
31
32        macro_rules! resolve_base {
33            ($base:expr) => {
34                match &mut $base {
35                    Base::None => (),
36                    Base::Extension(x) => *x = typedefs.resolve(x).clone(),
37                    Base::Restriction(x) => *x = typedefs.resolve(x).clone(),
38                }
39            };
40        }
41
42        let mut replaced_references = HashMap::new();
43
44        for type_ in self.types.values_mut() {
45            match &mut type_.variant {
46                TypeVariant::Reference(x) if x.is_single() => {
47                    let new_type = typedefs.resolve(&x.type_).clone();
48                    replaced_references
49                        .entry(x.type_.clone())
50                        .or_insert_with(|| new_type.clone());
51                    x.type_ = new_type;
52                }
53                TypeVariant::Union(x) => {
54                    resolve_base!(&mut x.base);
55
56                    for x in &mut *x.types {
57                        x.type_ = typedefs.resolve(&x.type_).clone();
58                    }
59                }
60                TypeVariant::Dynamic(x) => {
61                    x.type_ = x.type_.as_ref().map(|x| typedefs.resolve(x)).cloned();
62
63                    for x in &mut x.derived_types {
64                        *x = typedefs.resolve(x).clone();
65                    }
66                }
67                TypeVariant::Enumeration(x) => {
68                    resolve_base!(&mut x.base);
69
70                    for x in &mut *x.variants {
71                        if let Some(x) = &mut x.type_ {
72                            *x = typedefs.resolve(x).clone();
73                        }
74                    }
75                }
76                TypeVariant::ComplexType(x) => {
77                    resolve_base!(&mut x.base);
78
79                    if let Some(ident) = &mut x.content {
80                        *ident = typedefs.resolve(ident).clone();
81                    }
82
83                    for attrib in &mut *x.attributes {
84                        attrib.type_ = typedefs.resolve(&attrib.type_).clone();
85                    }
86                }
87                TypeVariant::All(x) | TypeVariant::Choice(x) | TypeVariant::Sequence(x) => {
88                    for element in &mut *x.elements {
89                        element.type_ = typedefs.resolve(&element.type_).clone();
90                    }
91                }
92                _ => (),
93            }
94        }
95
96        for type_ in self.types.values_mut() {
97            let TypeVariant::Dynamic(di) = &mut type_.variant else {
98                continue;
99            };
100
101            for derived in &mut di.derived_types {
102                if let Some(new_type) = replaced_references.get(derived) {
103                    *derived = new_type.clone();
104                }
105            }
106        }
107
108        self
109    }
110}