xsd_parser/pipeline/optimizer/
empty_unions.rs

1use std::collections::HashSet;
2
3use crate::models::meta::{MetaTypeVariant, ReferenceMeta};
4
5use super::{get_typedefs, Optimizer};
6
7impl Optimizer {
8    /// This will remove variants of an union, if the type of the variant resolves
9    /// to the same type as an other variant. In other words, the variant will be
10    /// removed if the types are identical.
11    ///
12    /// # Examples
13    ///
14    /// Consider the following XML schema. `xs:language` and `xs:string` are both
15    /// type definitions for [`String`].
16    /// ```xml
17    #[doc = include_str!("../../../tests/optimizer/union_duplicate.xsd")]
18    /// ```
19    ///
20    /// Without this optimization this will result in the following code:
21    /// ```rust
22    #[doc = include_str!("../../../tests/optimizer/expected0/remove_duplicate_union_variants.rs")]
23    /// ```
24    ///
25    /// With this optimization the following code is generated:
26    /// ```rust
27    #[doc = include_str!("../../../tests/optimizer/expected1/remove_duplicate_union_variants.rs")]
28    /// ```
29    pub fn remove_duplicate_union_variants(mut self) -> Self {
30        tracing::debug!("remove_duplicate_union_variants");
31
32        let typedefs = get_typedefs!(self);
33
34        for type_ in self.types.items.values_mut() {
35            if let MetaTypeVariant::Union(x) = &mut type_.variant {
36                let mut i = 0;
37                let mut types_ = HashSet::new();
38
39                while i < x.types.len() {
40                    let type_ = typedefs.resolve(&x.types[i].type_).clone();
41                    if types_.insert(type_) {
42                        i += 1;
43                    } else {
44                        x.types.remove(i);
45                    }
46                }
47            }
48        }
49
50        self
51    }
52
53    /// This will replace an union with a simple type definition, if the union
54    /// has only one variant.
55    ///
56    /// # Examples
57    ///
58    /// Consider the following XML schema.
59    /// ```xml
60    #[doc = include_str!("../../../tests/optimizer/union_empty.xsd")]
61    /// ```
62    ///
63    /// Without this optimization this will result in the following code:
64    /// ```rust
65    #[doc = include_str!("../../../tests/optimizer/expected0/remove_empty_unions.rs")]
66    /// ```
67    ///
68    /// With this optimization the following code is generated:
69    /// ```rust
70    #[doc = include_str!("../../../tests/optimizer/expected1/remove_empty_unions.rs")]
71    /// ```
72    pub fn remove_empty_unions(mut self) -> Self {
73        tracing::debug!("remove_empty_unions");
74
75        for type_ in self.types.items.values_mut() {
76            if let MetaTypeVariant::Union(x) = &type_.variant {
77                if x.types.len() <= 1 {
78                    let base = x.types.first().map(|x| &x.type_).or(x.base.as_ident());
79                    if let Some(base) = base {
80                        self.typedefs = None;
81                        type_.variant =
82                            MetaTypeVariant::Reference(ReferenceMeta::new(base.clone()));
83                    }
84                }
85            }
86        }
87
88        self
89    }
90}