xsd_parser/optimizer/
mod.rs

1//! The `optimizer` module contains the type information [`Optimizer`] and all related types.
2
3use std::collections::{HashMap, HashSet};
4use std::hash::{Hash, Hasher};
5
6use crate::{
7    schema::{MaxOccurs, MinOccurs},
8    types::{
9        Base, ComplexInfo, ElementInfo, ElementMode, EnumerationInfo, GroupInfo, Ident, Name,
10        ReferenceInfo, Type, TypeEq, Types, UnionInfo, UnionTypeInfo, VariantInfo, VecHelper,
11    },
12};
13
14/// The [`Optimizer`] is a structure that can be used to reduce the size and the
15/// complexity of a [`Types`] instance.
16///
17/// The optimizer contains different optimizations that could be applied to a
18/// [`Types`] instance. Optimizations are usually used to reduce the size or the
19/// complexity of the different types.
20#[must_use]
21#[derive(Debug)]
22pub struct Optimizer {
23    types: Types,
24    bases: Option<BaseMap>,
25    typedefs: Option<TypedefMap>,
26}
27
28#[derive(Debug)]
29struct BaseMap(HashMap<Ident, Base>);
30
31#[derive(Debug)]
32struct TypedefMap(HashMap<Ident, Ident>);
33
34struct FlattenComplexInfo {
35    info: GroupInfo,
36    count: usize,
37    is_choice: bool,
38}
39
40struct FlattenUnionInfo {
41    count: usize,
42    info: UnionInfo,
43}
44
45macro_rules! get_bases {
46    ($this:expr) => {{
47        if $this.bases.is_none() {
48            $this.bases = Some(BaseMap::new(&$this.types));
49        }
50
51        $this.bases.as_ref().unwrap()
52    }};
53}
54
55macro_rules! get_typedefs {
56    ($this:expr) => {{
57        if $this.typedefs.is_none() {
58            $this.typedefs = Some(TypedefMap::new(&$this.types));
59        }
60
61        $this.typedefs.as_ref().unwrap()
62    }};
63}
64
65impl Optimizer {
66    /// Create a new [`Optimizer`] instance from the passed `types`.
67    pub fn new(types: Types) -> Self {
68        Self {
69            types,
70            bases: None,
71            typedefs: None,
72        }
73    }
74
75    /// Finish the optimization and return the resulting [`Types`].
76    #[must_use]
77    pub fn finish(self) -> Types {
78        self.types
79    }
80
81    /// This will remove any enum variant that has an empty string as name.
82    ///
83    /// # Examples
84    ///
85    /// Consider the following XML schema:
86    /// ```xml
87    #[doc = include_str!("../../tests/optimizer/enum_empty_variant.xsd")]
88    /// ```
89    ///
90    /// Without this optimization this will result in the following code:
91    /// ```rust
92    #[doc = include_str!("../../tests/optimizer/expected0/remove_empty_enum_variants.rs")]
93    /// ```
94    ///
95    /// With this optimization the following code is generated:
96    /// ```rust
97    #[doc = include_str!("../../tests/optimizer/expected1/remove_empty_enum_variants.rs")]
98    /// ```
99    pub fn remove_empty_enum_variants(mut self) -> Self {
100        tracing::debug!("remove_empty_enum_variants");
101
102        for type_ in self.types.types.values_mut() {
103            if let Type::Enumeration(x) = type_ {
104                x.variants
105                    .retain(|x| !matches!(&x.ident.name, Name::Named(x) if x.is_empty()));
106            }
107        }
108
109        self
110    }
111
112    /// This will remove replace the enum with a type reference to the enums base
113    /// type if the enum does not have any variant.
114    ///
115    /// This optimization is usually used in combination with
116    /// [`remove_empty_enum_variants`](Self::remove_empty_enum_variants).
117    ///
118    /// # Examples
119    ///
120    /// Consider the following XML schema:
121    /// ```xml
122    #[doc = include_str!("../../tests/optimizer/enum_empty.xsd")]
123    /// ```
124    ///
125    /// Without this optimization this will result in the following code:
126    /// ```rust
127    #[doc = include_str!("../../tests/optimizer/expected0/remove_empty_enums.rs")]
128    /// ```
129    ///
130    /// With this optimization (and the [`remove_empty_enum_variants`](Self::remove_empty_enum_variants))
131    /// the following code is generated:
132    /// ```rust
133    #[doc = include_str!("../../tests/optimizer/expected1/remove_empty_enums.rs")]
134    /// ```
135    pub fn remove_empty_enums(mut self) -> Self {
136        tracing::debug!("remove_empty_enums");
137
138        for type_ in self.types.types.values_mut() {
139            if let Type::Enumeration(x) = type_ {
140                if x.variants.is_empty() {
141                    if let Some(base) = x.base.as_ident() {
142                        self.typedefs = None;
143                        *type_ = Type::Reference(ReferenceInfo::new(base.clone()));
144                    }
145                }
146            }
147        }
148
149        self
150    }
151
152    /// This will remove variants of an union, if the type of the variant resolves
153    /// to the same type as an other variant. In other words, the variant will be
154    /// removed if the types are identical.
155    ///
156    /// # Examples
157    ///
158    /// Consider the following XML schema. `xs:language` and `xs:string` are both
159    /// type definitions for [`String`].
160    /// ```xml
161    #[doc = include_str!("../../tests/optimizer/union_duplicate.xsd")]
162    /// ```
163    ///
164    /// Without this optimization this will result in the following code:
165    /// ```rust
166    #[doc = include_str!("../../tests/optimizer/expected0/remove_duplicate_union_variants.rs")]
167    /// ```
168    ///
169    /// With this optimization the following code is generated:
170    /// ```rust
171    #[doc = include_str!("../../tests/optimizer/expected1/remove_duplicate_union_variants.rs")]
172    /// ```
173    pub fn remove_duplicate_union_variants(mut self) -> Self {
174        tracing::debug!("remove_duplicate_union_variants");
175
176        let typedefs = get_typedefs!(self);
177
178        for type_ in self.types.types.values_mut() {
179            if let Type::Union(x) = type_ {
180                let mut i = 0;
181                let mut types_ = HashSet::new();
182
183                while i < x.types.len() {
184                    let type_ = typedefs.resolve(&x.types[i].type_).clone();
185                    if types_.insert(type_) {
186                        i += 1;
187                    } else {
188                        x.types.remove(i);
189                    }
190                }
191            }
192        }
193
194        self
195    }
196
197    /// This will replace an union with a simple type definition, if the union
198    /// has only one variant.
199    ///
200    /// # Examples
201    ///
202    /// Consider the following XML schema.
203    /// ```xml
204    #[doc = include_str!("../../tests/optimizer/union_empty.xsd")]
205    /// ```
206    ///
207    /// Without this optimization this will result in the following code:
208    /// ```rust
209    #[doc = include_str!("../../tests/optimizer/expected0/remove_empty_unions.rs")]
210    /// ```
211    ///
212    /// With this optimization the following code is generated:
213    /// ```rust
214    #[doc = include_str!("../../tests/optimizer/expected1/remove_empty_unions.rs")]
215    /// ```
216    pub fn remove_empty_unions(mut self) -> Self {
217        tracing::debug!("remove_empty_unions");
218
219        for type_ in self.types.types.values_mut() {
220            if let Type::Union(x) = type_ {
221                if x.types.len() <= 1 {
222                    let base = x.types.first().map(|x| &x.type_).or(x.base.as_ident());
223                    if let Some(base) = base {
224                        self.typedefs = None;
225                        *type_ = Type::Reference(ReferenceInfo::new(base.clone()));
226                    }
227                }
228            }
229        }
230
231        self
232    }
233
234    /// This will use the unrestricted base type instead more the restricted
235    /// version when ever possible.
236    ///
237    /// This is useful if you want to reduce the amount of different type, then
238    /// the base type can store the same data than the restricted one.
239    /// However this is only useful if you want to deserialize the type only. Using
240    /// this feature for serializing types will cause problems because the type
241    /// information is dropped during deserialization.
242    ///
243    /// # Examples
244    ///
245    /// Consider the following XML schema.
246    /// ```xml
247    #[doc = include_str!("../../tests/optimizer/complex_restricted.xsd")]
248    /// ```
249    ///
250    /// Without this optimization this will result in the following code:
251    /// ```rust
252    #[doc = include_str!("../../tests/optimizer/expected0/use_unrestricted_base_type.rs")]
253    /// ```
254    ///
255    /// With this optimization the following code is generated:
256    /// ```rust
257    #[doc = include_str!("../../tests/optimizer/expected1/use_unrestricted_base_type.rs")]
258    /// ```
259    pub fn use_unrestricted_base_type(mut self) -> Self {
260        tracing::debug!("use_unrestricted_base_type");
261
262        let bases = get_bases!(self);
263
264        for (ident, type_) in &mut *self.types {
265            match type_ {
266                Type::ComplexType(_) | Type::Enumeration(_) | Type::Union(_) => {
267                    let base = bases.get_unrestricted(ident).clone();
268                    if *ident != base {
269                        self.typedefs = None;
270                        *type_ = Type::Reference(ReferenceInfo::new(base));
271                    }
272                }
273                _ => (),
274            }
275        }
276
277        self
278    }
279
280    /// This will use a enum that contains all known variants of the dynamic
281    /// type instead of a dynamic box.
282    ///
283    /// # Examples
284    ///
285    /// Consider the following XML schema.
286    /// ```xml
287    #[doc = include_str!("../../tests/optimizer/abstract.xsd")]
288    /// ```
289    ///
290    /// Without this optimization this will result in the following code:
291    /// ```rust
292    #[doc = include_str!("../../tests/optimizer/expected0/convert_dynamic_to_choice.rs")]
293    /// ```
294    ///
295    /// With this optimization the following code is generated:
296    /// ```rust
297    #[doc = include_str!("../../tests/optimizer/expected1/convert_dynamic_to_choice.rs")]
298    /// ```
299    pub fn convert_dynamic_to_choice(mut self) -> Self {
300        use std::collections::btree_map::Entry;
301
302        tracing::debug!("convert_dynamic_to_choice");
303
304        let idents = self
305            .types
306            .iter()
307            .filter_map(|(ident, ty)| {
308                if matches!(ty, Type::Dynamic(_)) {
309                    Some(ident)
310                } else {
311                    None
312                }
313            })
314            .cloned()
315            .collect::<Vec<_>>();
316
317        for ident in idents {
318            let content_ident = Ident::new(self.types.make_unnamed()).with_ns(ident.ns);
319
320            let type_ = self.types.get_mut(&ident).unwrap();
321            let Type::Dynamic(x) = type_ else {
322                crate::unreachable!();
323            };
324
325            let mut si = GroupInfo::default();
326            for derived in &x.derived_types {
327                si.elements.find_or_insert(derived.clone(), |ident| {
328                    ElementInfo::new(ident, derived.clone(), ElementMode::Element)
329                });
330            }
331
332            *type_ = Type::ComplexType(ComplexInfo {
333                content: Some(content_ident.clone()),
334                is_dynamic: true,
335                ..Default::default()
336            });
337
338            match self.types.entry(content_ident) {
339                Entry::Vacant(e) => {
340                    e.insert(Type::Choice(si));
341                }
342                Entry::Occupied(_) => crate::unreachable!(),
343            }
344        }
345
346        self
347    }
348
349    /// This will flatten the nested groups (`xs::all`, `xs::choice` or `xs::sequence`)
350    /// to one type instead of rendering nested structures.
351    ///
352    /// # Examples
353    ///
354    /// Consider the following XML schema.
355    /// ```xml
356    #[doc = include_str!("../../tests/optimizer/complex_flatten.xsd")]
357    /// ```
358    ///
359    /// Without this optimization this will result in the following code:
360    /// ```rust
361    #[doc = include_str!("../../tests/optimizer/expected0/flatten_element_content.rs")]
362    /// ```
363    ///
364    /// With this optimization the following code is generated:
365    /// ```rust
366    #[doc = include_str!("../../tests/optimizer/expected1/flatten_element_content.rs")]
367    /// ```
368    pub fn flatten_element_content(mut self) -> Self {
369        tracing::debug!("flatten_element_content");
370
371        let idents = self
372            .types
373            .iter()
374            .filter_map(|(ident, type_)| {
375                if matches!(type_, Type::ComplexType(ci) if ci.has_complex_content(&self.types)) {
376                    Some(ident)
377                } else {
378                    None
379                }
380            })
381            .cloned()
382            .collect::<Vec<_>>();
383
384        for ident in idents {
385            let type_ = self.types.get(&ident).unwrap();
386            let Type::ComplexType(ci) = type_ else {
387                crate::unreachable!();
388            };
389            let Some(content_ident) = ci.content.clone() else {
390                continue;
391            };
392
393            let mut info = FlattenComplexInfo {
394                info: GroupInfo::default(),
395                count: 0,
396                is_choice: false,
397            };
398
399            self.flatten_complex(&content_ident, ci.min_occurs, ci.max_occurs, &mut info);
400
401            if info.count > 1 {
402                let type_ = if info.is_choice {
403                    Type::Choice(info.info)
404                } else {
405                    Type::Sequence(info.info)
406                };
407
408                self.types.insert(content_ident, type_);
409            }
410        }
411
412        self
413    }
414
415    /// This will flatten nested union types to one single union.
416    ///
417    /// # Examples
418    ///
419    /// Consider the following XML schema.
420    /// ```xml
421    #[doc = include_str!("../../tests/optimizer/union_flatten.xsd")]
422    /// ```
423    ///
424    /// Without this optimization this will result in the following code:
425    /// ```rust
426    #[doc = include_str!("../../tests/optimizer/expected0/flatten_unions.rs")]
427    /// ```
428    ///
429    /// With this optimization the following code is generated:
430    /// ```rust
431    #[doc = include_str!("../../tests/optimizer/expected1/flatten_unions.rs")]
432    /// ```
433    pub fn flatten_unions(mut self) -> Self {
434        tracing::debug!("flatten_unions");
435
436        let idents = self
437            .types
438            .iter()
439            .filter_map(|(ident, type_)| {
440                if matches!(type_, Type::Union(_)) {
441                    Some(ident)
442                } else {
443                    None
444                }
445            })
446            .cloned()
447            .collect::<Vec<_>>();
448
449        for ident in idents {
450            let Some(Type::Union(x)) = self.types.get(&ident) else {
451                continue;
452            };
453            let mut info = FlattenUnionInfo {
454                count: 0,
455                info: UnionInfo::default(),
456            };
457            self.flatten_union(&ident, None, &mut info);
458            if info.count > 1 {
459                info.info.base = x.base.clone();
460
461                self.types.insert(ident, Type::Union(info.info));
462            }
463        }
464
465        self
466    }
467
468    /// This will flatten nested union and enum types to one single enum type.
469    ///
470    /// # Examples
471    ///
472    /// Consider the following XML schema.
473    /// ```xml
474    #[doc = include_str!("../../tests/optimizer/union_flatten.xsd")]
475    /// ```
476    ///
477    /// Without this optimization this will result in the following code:
478    /// ```rust
479    #[doc = include_str!("../../tests/optimizer/expected0/merge_enum_unions.rs")]
480    /// ```
481    ///
482    /// With this optimization the following code is generated:
483    /// ```rust
484    #[doc = include_str!("../../tests/optimizer/expected1/merge_enum_unions.rs")]
485    /// ```
486    pub fn merge_enum_unions(mut self) -> Self {
487        tracing::debug!("merge_enum_unions");
488
489        let idents = self
490            .types
491            .iter()
492            .filter_map(|(ident, type_)| {
493                if matches!(type_, Type::Union(_)) {
494                    Some(ident)
495                } else {
496                    None
497                }
498            })
499            .cloned()
500            .collect::<Vec<_>>();
501
502        for ident in idents {
503            let Some(Type::Union(_)) = self.types.get(&ident) else {
504                continue;
505            };
506            let mut next = None;
507            self.flatten_enum_union(&ident, None, &mut next);
508            if let Some(next) = next {
509                self.types.insert(ident, next);
510            }
511        }
512
513        self
514    }
515
516    /// This will resolve all simple type definitions and use the target type
517    /// directly.
518    ///
519    /// # Examples
520    ///
521    /// Consider the following XML schema.
522    /// ```xml
523    #[doc = include_str!("../../tests/optimizer/complex_flatten.xsd")]
524    /// ```
525    ///
526    /// Without this optimization this will result in the following code:
527    /// ```rust
528    #[doc = include_str!("../../tests/optimizer/expected0/resolve_typedefs.rs")]
529    /// ```
530    ///
531    /// With this optimization the following code is generated:
532    /// ```rust
533    #[doc = include_str!("../../tests/optimizer/expected1/resolve_typedefs.rs")]
534    /// ```
535    pub fn resolve_typedefs(mut self) -> Self {
536        tracing::debug!("resolve_typedefs");
537
538        let typedefs = get_typedefs!(self);
539
540        macro_rules! resolve_base {
541            ($base:expr) => {
542                match &mut $base {
543                    Base::None => (),
544                    Base::Extension(x) => *x = typedefs.resolve(x).clone(),
545                    Base::Restriction(x) => *x = typedefs.resolve(x).clone(),
546                }
547            };
548        }
549
550        let mut replaced_references = HashMap::new();
551
552        for type_ in self.types.values_mut() {
553            match type_ {
554                Type::Reference(x) if x.is_single() => {
555                    let new_type = typedefs.resolve(&x.type_).clone();
556                    replaced_references
557                        .entry(x.type_.clone())
558                        .or_insert_with(|| new_type.clone());
559                    x.type_ = new_type;
560                }
561                Type::Union(x) => {
562                    resolve_base!(&mut x.base);
563
564                    for x in &mut *x.types {
565                        x.type_ = typedefs.resolve(&x.type_).clone();
566                    }
567                }
568                Type::Dynamic(x) => {
569                    x.type_ = x.type_.as_ref().map(|x| typedefs.resolve(x)).cloned();
570
571                    for x in &mut x.derived_types {
572                        *x = typedefs.resolve(x).clone();
573                    }
574                }
575                Type::Enumeration(x) => {
576                    resolve_base!(&mut x.base);
577
578                    for x in &mut *x.variants {
579                        if let Some(x) = &mut x.type_ {
580                            *x = typedefs.resolve(x).clone();
581                        }
582                    }
583                }
584                Type::ComplexType(x) => {
585                    resolve_base!(&mut x.base);
586
587                    if let Some(ident) = &mut x.content {
588                        *ident = typedefs.resolve(ident).clone();
589                    }
590
591                    for attrib in &mut *x.attributes {
592                        attrib.type_ = typedefs.resolve(&attrib.type_).clone();
593                    }
594                }
595                Type::All(x) | Type::Choice(x) | Type::Sequence(x) => {
596                    for element in &mut *x.elements {
597                        element.type_ = typedefs.resolve(&element.type_).clone();
598                    }
599                }
600                _ => (),
601            }
602        }
603
604        for type_ in self.types.values_mut() {
605            let Type::Dynamic(ai) = type_ else {
606                continue;
607            };
608
609            for derived in &mut ai.derived_types {
610                if let Some(new_type) = replaced_references.get(derived) {
611                    *derived = new_type.clone();
612                }
613            }
614        }
615
616        self
617    }
618
619    /// If two types are completely equal this optimization will generate the
620    /// first type complete and just a type definition for the second one.
621    ///
622    /// <div class="warning">
623    /// *Caution*
624    ///
625    /// Be careful with this optimization. This will compare each known
626    /// type with each other type and check if the types are identical or not.
627    /// This would result in a type reference for two types, even if the types
628    /// itself are not logically related to each other.
629    ///
630    /// Furthermore this may result in typedef loops. The code generator should
631    /// be able to deal with them (using a Box), but it is still risky to use it.
632    /// </div>
633    ///
634    /// # Examples
635    ///
636    /// Consider the following XML schema.
637    /// ```xml
638    #[doc = include_str!("../../tests/optimizer/duplicate.xsd")]
639    /// ```
640    ///
641    /// Without this optimization this will result in the following code:
642    /// ```rust
643    #[doc = include_str!("../../tests/optimizer/expected0/remove_duplicates.rs")]
644    /// ```
645    ///
646    /// With this optimization the following code is generated:
647    /// ```rust
648    #[doc = include_str!("../../tests/optimizer/expected1/remove_duplicates.rs")]
649    /// ```
650    pub fn remove_duplicates(mut self) -> Self {
651        use std::collections::hash_map::Entry;
652
653        struct Value<'a> {
654            type_: &'a Type,
655            types: &'a Types,
656        }
657
658        impl PartialEq for Value<'_> {
659            fn eq(&self, other: &Self) -> bool {
660                self.type_.type_eq(other.type_, self.types)
661            }
662        }
663
664        impl Eq for Value<'_> {}
665
666        impl Hash for Value<'_> {
667            fn hash<H: Hasher>(&self, state: &mut H) {
668                self.type_.type_hash(state, self.types);
669            }
670        }
671
672        tracing::debug!("remove_duplicates");
673
674        let mut changed = true;
675
676        while changed {
677            changed = false;
678
679            tracing::trace!("remove_duplicates new iteration");
680
681            let types = &self.types;
682
683            let mut map = HashMap::new();
684            let mut idents = HashMap::new();
685
686            for (ident, type_) in self.types.iter() {
687                match map.entry(Value { type_, types }) {
688                    Entry::Vacant(e) => {
689                        e.insert(ident.clone());
690                    }
691                    Entry::Occupied(e) => {
692                        let reference_ident = e.get();
693                        if !matches!(type_, Type::Reference(ti) if &ti.type_ == reference_ident) {
694                            idents.insert(ident.clone(), reference_ident.clone());
695                        }
696                    }
697                }
698            }
699
700            if !idents.is_empty() {
701                changed = true;
702                self.typedefs = None;
703            }
704
705            for (ident, referenced_type) in idents {
706                println!("Create reference for duplicate type: {ident} => {referenced_type}");
707
708                self.types
709                    .insert(ident, Type::Reference(ReferenceInfo::new(referenced_type)));
710            }
711        }
712
713        self
714    }
715
716    fn flatten_complex(
717        &self,
718        ident: &Ident,
719        min: MinOccurs,
720        max: MaxOccurs,
721        next: &mut FlattenComplexInfo,
722    ) {
723        let Some(type_) = self.types.get(ident) else {
724            return;
725        };
726
727        let mut is_choice = false;
728        let si = match type_ {
729            Type::Choice(si) => {
730                is_choice = true;
731                next.is_choice = true;
732
733                si
734            }
735            Type::All(si) | Type::Sequence(si) => si,
736            Type::Reference(ti) if ti.is_single() => {
737                self.flatten_complex(
738                    &ti.type_,
739                    min.min(ti.min_occurs),
740                    max.max(ti.max_occurs),
741                    next,
742                );
743
744                return;
745            }
746            x => crate::unreachable!("{x:#?}"),
747        };
748
749        next.count += 1;
750
751        for x in &*si.elements {
752            match x.element_mode {
753                ElementMode::Group => {
754                    let (min, max) = if is_choice {
755                        (min.min(x.min_occurs), max.max(x.max_occurs))
756                    } else {
757                        (min + x.min_occurs, max + x.max_occurs)
758                    };
759
760                    self.flatten_complex(&x.type_, min, max, next);
761                }
762                ElementMode::Element => {
763                    let element = next
764                        .info
765                        .elements
766                        .find_or_insert(x.ident.clone(), |_| x.clone());
767                    element.min_occurs = min.min(x.min_occurs);
768                    element.max_occurs = max.max(x.max_occurs);
769                }
770            }
771        }
772
773        if let Some(any) = &si.any {
774            next.info.any = Some(any.clone());
775        }
776    }
777
778    fn flatten_union(
779        &self,
780        ident: &Ident,
781        display_name: Option<&str>,
782        next: &mut FlattenUnionInfo,
783    ) {
784        let Some(type_) = self.types.get(ident) else {
785            return;
786        };
787
788        match type_ {
789            Type::Union(x) => {
790                next.count += 1;
791                for t in &*x.types {
792                    self.flatten_union(&t.type_, t.display_name.as_deref(), next);
793                }
794            }
795            Type::Reference(x) if x.is_single() => {
796                self.flatten_union(&x.type_, display_name, next);
797            }
798            _ => {
799                let mut ui = UnionTypeInfo::new(ident.clone());
800                ui.display_name = display_name.map(ToOwned::to_owned);
801
802                next.info.types.push(ui);
803            }
804        }
805    }
806
807    fn flatten_enum_union(
808        &self,
809        ident: &Ident,
810        display_name: Option<&str>,
811        next: &mut Option<Type>,
812    ) {
813        let Some(type_) = self.types.get(ident) else {
814            return;
815        };
816
817        match type_ {
818            Type::Union(x) => {
819                for t in &*x.types {
820                    self.flatten_enum_union(&t.type_, t.display_name.as_deref(), next);
821                }
822            }
823            Type::Enumeration(x) => {
824                *next = match next.take() {
825                    None => Some(Type::Enumeration(EnumerationInfo::default())),
826                    Some(Type::Enumeration(ei)) => Some(Type::Enumeration(ei)),
827                    Some(Type::Union(ui)) => {
828                        let mut ei = EnumerationInfo::default();
829
830                        for t in ui.types.0 {
831                            let var = ei.variants.find_or_insert(t.type_.clone(), |ident| {
832                                VariantInfo::new(ident).with_type(Some(t.type_.clone()))
833                            });
834                            var.display_name = t.display_name;
835                        }
836
837                        Some(Type::Enumeration(ei))
838                    }
839                    _ => crate::unreachable!(),
840                };
841
842                let Some(Type::Enumeration(ei)) = next else {
843                    crate::unreachable!();
844                };
845
846                for var in &*x.variants {
847                    let new_var = ei.variants.find_or_insert(var.ident.clone(), |ident| {
848                        VariantInfo::new(ident).with_type(var.type_.clone())
849                    });
850                    new_var.display_name.clone_from(&var.display_name);
851                }
852            }
853            Type::Reference(x) if x.is_single() => {
854                self.flatten_enum_union(&x.type_, display_name, next);
855            }
856            _ => {
857                if next.is_none() {
858                    *next = Some(Type::Union(UnionInfo::default()));
859                }
860
861                match next {
862                    Some(Type::Union(ui)) => {
863                        let mut ti = UnionTypeInfo::new(ident.clone());
864                        ti.display_name = display_name.map(ToOwned::to_owned);
865
866                        ui.types.push(ti);
867                    }
868                    Some(Type::Enumeration(ei)) => {
869                        let var = ei.variants.find_or_insert(ident.clone(), |x| {
870                            VariantInfo::new(x).with_type(Some(ident.clone()))
871                        });
872                        var.display_name = display_name.map(ToOwned::to_owned);
873                    }
874                    _ => crate::unreachable!(),
875                }
876            }
877        }
878    }
879}
880
881impl BaseMap {
882    fn new(types: &Types) -> Self {
883        let mut ret = HashMap::new();
884
885        for (ident, type_) in &types.types {
886            match type_ {
887                Type::Enumeration(ei) => {
888                    if matches!(
889                        ei.base.as_ident().and_then(|base| types.get(base)),
890                        Some(Type::Enumeration(_))
891                    ) {
892                        ret.insert(ident.clone(), ei.base.clone());
893                    }
894                }
895                Type::Union(ei) => {
896                    if matches!(
897                        ei.base.as_ident().and_then(|base| types.get(base)),
898                        Some(Type::Union(_))
899                    ) {
900                        ret.insert(ident.clone(), ei.base.clone());
901                    }
902                }
903                Type::ComplexType(ci) => {
904                    if matches!(
905                        ci.base.as_ident().and_then(|base| types.get(base)),
906                        Some(Type::ComplexType(_))
907                    ) {
908                        ret.insert(ident.clone(), ci.base.clone());
909                    }
910                }
911                _ => (),
912            }
913        }
914
915        Self(ret)
916    }
917
918    fn get_unrestricted<'a>(&'a self, ident: &'a Ident) -> &'a Ident {
919        match self.0.get(ident) {
920            Some(Base::Restriction(base)) => self.get_unrestricted(base),
921            _ => ident,
922        }
923    }
924}
925
926impl TypedefMap {
927    fn new(types: &Types) -> Self {
928        let mut ret = HashMap::new();
929
930        for (ident, type_) in &types.types {
931            if let Type::Reference(x) = type_ {
932                if x.is_single() {
933                    ret.insert(ident.clone(), x.type_.clone());
934                }
935            }
936        }
937
938        Self(ret)
939    }
940
941    fn resolve<'a>(&'a self, ident: &'a Ident) -> &'a Ident {
942        let x = self.0.get(ident).map_or(ident, |x| self.resolve(x));
943
944        x
945    }
946}