pub struct Optimizer { /* private fields */ }
Expand description
Optimizes a MetaTypes
structure by reducing redundant or verbose type definitions.
The Optimizer
performs various semantic transformations on a type graph,
such as flattening unions, removing empty enums, simplifying typedef chains,
and reducing nested complex structures.
It is typically used after schema interpretation and before code generation, to ensure that only necessary and well-structured types are preserved in the final output.
Optimization is performed lazily; the resulting MetaTypes
can be retrieved
using finish
.
Implementations§
Source§impl Optimizer
impl Optimizer
Sourcepub fn convert_dynamic_to_choice(self) -> Self
pub fn convert_dynamic_to_choice(self) -> Self
This will use a enum that contains all known variants of the dynamic type instead of a dynamic box.
§Examples
Consider the following XML schema.
<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:tns="http://example.com"
targetNamespace="http://example.com">
<xs:element name="Abstract" abstract="true" />
<xs:element name="First" substitutionGroup="tns:Abstract">
<xs:complexType>
<xs:sequence>
<xs:element name="a" type="xs:string" />
</xs:sequence>
</xs:complexType>
</xs:element>
<xs:element name="Second" substitutionGroup="tns:Abstract">
<xs:simpleType>
<xs:restriction base="xs:token">
<xs:enumeration value="Var1" />
<xs:enumeration value="Var2" />
</xs:restriction>
</xs:simpleType>
</xs:element>
</xs:schema>
Without this optimization this will result in the following code:
use xsd_parser::AsAny;
pub struct Abstract(pub Box<dyn AbstractTrait>);
pub trait AbstractTrait: AsAny {}
pub struct FirstType {
pub a: String,
}
impl AbstractTrait for FirstType {}
pub enum SecondType {
Var1,
Var2,
}
impl AbstractTrait for SecondType {}
With this optimization the following code is generated:
pub struct Abstract {
pub content: AbstractContent,
}
pub enum AbstractContent {
First(FirstType),
Second(SecondType),
}
pub struct FirstType {
pub a: String,
}
pub enum SecondType {
Var1,
Var2,
}
Source§impl Optimizer
impl Optimizer
Sourcepub fn remove_empty_enum_variants(self) -> Self
pub fn remove_empty_enum_variants(self) -> Self
This will remove any enum variant that has an empty string as name.
§Examples
Consider the following XML schema:
<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:tns="http://example.com"
targetNamespace="http://example.com">
<xs:simpleType name="MyEnum">
<xs:restriction base="xs:string">
<xs:enumeration value="" />
<xs:enumeration value="Var1" />
<xs:enumeration value="Var2" />
</xs:restriction>
</xs:simpleType>
</xs:schema>
Without this optimization this will result in the following code:
pub enum MyEnumType {
Unknown1,
Var1,
Var2,
}
With this optimization the following code is generated:
pub enum MyEnumType {
Var1,
Var2,
}
Sourcepub fn remove_empty_enums(self) -> Self
pub fn remove_empty_enums(self) -> Self
This will replace the enum with a type reference to the enums base type if the enum does not have any variant.
This optimization is usually used in combination with
remove_empty_enum_variants
.
§Examples
Consider the following XML schema:
<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:tns="http://example.com"
targetNamespace="http://example.com">
<xs:simpleType name="MyEnum">
<xs:restriction base="xs:string">
<xs:enumeration value="" />
</xs:restriction>
</xs:simpleType>
</xs:schema>
Without this optimization this will result in the following code:
pub enum MyEnumType {
Unknown1,
}
With this optimization (and the remove_empty_enum_variants
)
the following code is generated:
pub type MyEnumType = String;
Source§impl Optimizer
impl Optimizer
Sourcepub fn remove_duplicate_union_variants(self) -> Self
pub fn remove_duplicate_union_variants(self) -> Self
This will remove variants of an union, if the type of the variant resolves to the same type as an other variant. In other words, the variant will be removed if the types are identical.
§Examples
Consider the following XML schema. xs:language
and xs:string
are both
type definitions for String
.
<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:tns="http://example.com"
targetNamespace="http://example.com">
<xs:simpleType name="MyUnion">
<xs:union memberTypes="xs:language xs:string" />
</xs:simpleType>
</xs:schema>
Without this optimization this will result in the following code:
pub enum MyUnionType {
Language(LanguageType),
String(StringType),
}
pub type LanguageType = String;
pub type StringType = String;
With this optimization the following code is generated:
pub enum MyUnionType {
Language(LanguageType),
}
pub type LanguageType = String;
Sourcepub fn remove_empty_unions(self) -> Self
pub fn remove_empty_unions(self) -> Self
This will replace an union with a simple type definition, if the union has only one variant.
§Examples
Consider the following XML schema.
<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:tns="http://example.com"
targetNamespace="http://example.com">
<xs:simpleType name="MyUnion">
<xs:union memberTypes="xs:string" />
</xs:simpleType>
</xs:schema>
Without this optimization this will result in the following code:
pub enum MyUnionType {
String(String),
}
With this optimization the following code is generated:
pub type MyUnionType = String;
Source§impl Optimizer
impl Optimizer
Sourcepub fn flatten_complex_type(self, ident: Ident) -> Result<Self, Error>
pub fn flatten_complex_type(self, ident: Ident) -> Result<Self, Error>
This will flatten the nested groups (xs::all
, xs::choice
or xs::sequence
)
of the complex type identified by ident
to one type instead of rendering
nested structures.
§Errors
Returns an error if the passed ident
could not be found, the referenced
type is not complex type or the complex type has no content.
§Examples
Consider the following XML schema.
<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:tns="http://example.com"
targetNamespace="http://example.com">
<xs:complexType name="MyComplexType">
<xs:sequence>
<xs:element name="ElementA" type="xs:string" minOccurs="0" maxOccurs="unbounded" />
<xs:element name="ElementB" type="xs:int" minOccurs="0" maxOccurs="unbounded" />
<xs:choice>
<xs:element name="ElementC" type="xs:boolean" />
<xs:sequence minOccurs="0">
<xs:element name="ElementD" type="xs:string" />
<xs:element name="ElementE" type="xs:int" />
</xs:sequence>
<xs:sequence>
<xs:element name="ElementF" type="xs:string" />
<xs:element name="ElementG" type="xs:int" maxOccurs="unbounded" />
</xs:sequence>
</xs:choice>
</xs:sequence>
</xs:complexType>
</xs:schema>
Without this optimization this will result in the following code:
pub struct MyComplexType {
pub element_a: Vec<String>,
pub element_b: Vec<i32>,
pub content_2: MyComplexContent2Type,
}
pub struct MyComplexContent2Type {
pub content: MyComplexContent2TypeContent,
}
pub enum MyComplexContent2TypeContent {
ElementC(bool),
Content3(Option<MyComplexContent3Type>),
Content4(MyComplexContent4Type),
}
pub struct MyComplexContent3Type {
pub element_d: String,
pub element_e: i32,
}
pub struct MyComplexContent4Type {
pub element_f: String,
pub element_g: Vec<i32>,
}
With this optimization the following code is generated:
pub struct MyComplexType {
pub content: Vec<MyComplexTypeContent>,
}
pub enum MyComplexTypeContent {
ElementA(String),
ElementB(i32),
ElementC(bool),
ElementD(String),
ElementE(i32),
ElementF(String),
ElementG(i32),
}
Sourcepub fn flatten_complex_types(self) -> Self
pub fn flatten_complex_types(self) -> Self
This will flatten all complex types.
For details see flatten_complex_type
.
Source§impl Optimizer
impl Optimizer
Sourcepub fn flatten_union(self, ident: Ident) -> Result<Self, Error>
pub fn flatten_union(self, ident: Ident) -> Result<Self, Error>
This will flatten the union identified by ident
to one single union.
§Errors
Returns an error if the passed ident
could not be found,
or is not an union.
§Examples
Consider the following XML schema.
<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:tns="http://example.com"
targetNamespace="http://example.com">
<xs:simpleType name="MyBaseUnion">
<xs:union memberTypes="xs:int">
<xs:simpleType>
<xs:list itemType="xs:unsignedInt" />
</xs:simpleType>
</xs:union>
</xs:simpleType>
<xs:simpleType name="MyEnum">
<xs:restriction base="xs:string">
<xs:enumeration value="Var1" />
<xs:enumeration value="Var2" />
</xs:restriction>
</xs:simpleType>
<xs:simpleType name="MyUnion">
<xs:union memberTypes="xs:string tns:MyEnum tns:MyBaseUnion" />
</xs:simpleType>
</xs:schema>
Without this optimization this will result in the following code:
pub enum MyUnionType {
String(String),
MyEnum(MyEnumType),
MyBaseUnion(MyBaseUnionType),
}
pub enum MyEnumType {
Var1,
Var2,
}
pub enum MyBaseUnionType {
I32(i32),
MyBaseUnion1(UnsignedIntList),
}
#[derive(Default)]
pub struct UnsignedIntList(pub Vec<UnsignedIntType>);
pub type UnsignedIntType = u32;
With this optimization the following code is generated:
pub enum MyUnionType {
String(String),
MyEnum(MyEnumType),
I32(i32),
MyBaseUnion1(UnsignedIntList),
}
pub enum MyEnumType {
Var1,
Var2,
}
#[derive(Default)]
pub struct UnsignedIntList(pub Vec<UnsignedIntType>);
pub type UnsignedIntType = u32;
Sourcepub fn flatten_unions(self) -> Self
pub fn flatten_unions(self) -> Self
This will flatten all union types.
For details see flatten_union
.
Source§impl Optimizer
impl Optimizer
Sourcepub fn merge_choice_cardinality(self, ident: Ident) -> Result<Self, Error>
pub fn merge_choice_cardinality(self, ident: Ident) -> Result<Self, Error>
This will merge the cardinality of each element of the complex choice
type identified by ident
with the cardinality of the types content.
§Errors
Returns an error if the passed ident
could not be found, the referenced
type is not complex type or the complex types content is not a choice.
§Examples
Consider the following XML schema.
<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:tns="http://example.com"
targetNamespace="http://example.com">
<xs:complexType name="MyComplexType">
<xs:choice>
<xs:element name="ElementA" type="xs:string" minOccurs="0" maxOccurs="unbounded" />
<xs:element name="ElementB" type="xs:int" minOccurs="0" maxOccurs="unbounded" />
<xs:element name="ElementC" type="xs:boolean" />
<xs:element name="ElementD" type="xs:string" minOccurs="0" />
<xs:element name="ElementE" type="xs:int" minOccurs="0" />
<xs:element name="ElementF" type="xs:string" />
<xs:element name="ElementG" type="xs:int" maxOccurs="unbounded" />
</xs:choice>
</xs:complexType>
</xs:schema>
Without this optimization this will result in the following code:
pub struct MyComplexType {
pub content: MyComplexTypeContent,
}
pub enum MyComplexTypeContent {
ElementA(Vec<String>),
ElementB(Vec<i32>),
ElementC(bool),
ElementD(Option<String>),
ElementE(Option<i32>),
ElementF(String),
ElementG(Vec<i32>),
}
With this optimization the following code is generated:
pub struct MyComplexType {
pub content: Vec<MyComplexTypeContent>,
}
pub enum MyComplexTypeContent {
ElementA(String),
ElementB(i32),
ElementC(bool),
ElementD(String),
ElementE(i32),
ElementF(String),
ElementG(i32),
}
Sourcepub fn merge_choice_cardinalities(self) -> Self
pub fn merge_choice_cardinalities(self) -> Self
This merge the cardinality of all elements of a choice with the content of the choice for all choice types.
For details see merge_choice_cardinality
.
Source§impl Optimizer
impl Optimizer
Sourcepub fn merge_enum_union(self, ident: Ident) -> Result<Self, Error>
pub fn merge_enum_union(self, ident: Ident) -> Result<Self, Error>
This will flatten the union identified by ident
to one single union.
This will merge the nested union and enum types of the union identified
by ident
to one single enum type.
§Errors
Returns an error if the passed ident
could not be found,
or is not an union.
§Examples
Consider the following XML schema.
<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:tns="http://example.com"
targetNamespace="http://example.com">
<xs:simpleType name="MyBaseUnion">
<xs:union memberTypes="xs:int">
<xs:simpleType>
<xs:list itemType="xs:unsignedInt" />
</xs:simpleType>
</xs:union>
</xs:simpleType>
<xs:simpleType name="MyEnum">
<xs:restriction base="xs:string">
<xs:enumeration value="Var1" />
<xs:enumeration value="Var2" />
</xs:restriction>
</xs:simpleType>
<xs:simpleType name="MyUnion">
<xs:union memberTypes="xs:string tns:MyEnum tns:MyBaseUnion" />
</xs:simpleType>
</xs:schema>
Without this optimization this will result in the following code:
pub enum MyUnionType {
String(String),
MyEnum(MyEnumType),
MyBaseUnion(MyBaseUnionType),
}
pub enum MyEnumType {
Var1,
Var2,
}
pub enum MyBaseUnionType {
I32(i32),
MyBaseUnion1(UnsignedIntList),
}
#[derive(Default)]
pub struct UnsignedIntList(pub Vec<UnsignedIntType>);
pub type UnsignedIntType = u32;
With this optimization the following code is generated:
pub enum MyUnionType {
String(String),
Var1,
Var2,
I32(i32),
UnsignedIntList(UnsignedIntList),
}
#[derive(Default)]
pub struct UnsignedIntList(pub Vec<UnsignedIntType>);
pub type UnsignedIntType = u32;
Sourcepub fn merge_enum_unions(self) -> Self
pub fn merge_enum_unions(self) -> Self
This will flatten all enumeration and union types.
For details see merge_enum_union
.
Source§impl Optimizer
impl Optimizer
Sourcepub fn remove_duplicates(self) -> Self
pub fn remove_duplicates(self) -> Self
If two types are completely equal this optimization will generate the first type complete and just a type definition for the second one.
Be careful with this optimization. This will compare each known type with each other type and check if the types are identical or not. This would result in a type reference for two types, even if the types itself are not logically related to each other.
Furthermore this may result in typedef loops. The code generator should be able to deal with them (using a Box), but it is still risky to use it.
§Examples
Consider the following XML schema.
<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:tns="http://example.com"
targetNamespace="http://example.com">
<xs:complexType name="First">
<xs:sequence>
<xs:element name="a" type="xs:string" />
<xs:element name="b" type="xs:string" minOccurs="0" />
<xs:element name="c" type="xs:string" maxOccurs="unbounded" />
</xs:sequence>
</xs:complexType>
<xs:complexType name="Second">
<xs:sequence>
<xs:element name="a" type="xs:string" />
<xs:element name="b" type="xs:string" minOccurs="0" />
<xs:element name="c" type="xs:string" maxOccurs="unbounded" />
</xs:sequence>
</xs:complexType>
</xs:schema>
Without this optimization this will result in the following code:
pub struct FirstType {
pub a: String,
pub b: Option<String>,
pub c: Vec<String>,
}
pub struct SecondType {
pub a: String,
pub b: Option<String>,
pub c: Vec<String>,
}
With this optimization the following code is generated:
pub struct FirstType {
pub a: String,
pub b: Option<String>,
pub c: Vec<String>,
}
pub type SecondType = FirstType;
Source§impl Optimizer
impl Optimizer
Sourcepub fn resolve_typedefs(self) -> Self
pub fn resolve_typedefs(self) -> Self
This will resolve all simple type definitions and use the target type directly.
§Examples
Consider the following XML schema.
<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:tns="http://example.com"
targetNamespace="http://example.com">
<xs:complexType name="MyComplexType">
<xs:sequence>
<xs:element name="ElementA" type="xs:string" minOccurs="0" maxOccurs="unbounded" />
<xs:element name="ElementB" type="xs:int" minOccurs="0" maxOccurs="unbounded" />
<xs:choice>
<xs:element name="ElementC" type="xs:boolean" />
<xs:sequence minOccurs="0">
<xs:element name="ElementD" type="xs:string" />
<xs:element name="ElementE" type="xs:int" />
</xs:sequence>
<xs:sequence>
<xs:element name="ElementF" type="xs:string" />
<xs:element name="ElementG" type="xs:int" maxOccurs="unbounded" />
</xs:sequence>
</xs:choice>
</xs:sequence>
</xs:complexType>
</xs:schema>
Without this optimization this will result in the following code:
pub struct MyComplexType {
pub element_a: Vec<StringType>,
pub element_b: Vec<IntType>,
pub content_2: MyComplexContent2Type,
}
pub type StringType = String;
pub type IntType = i32;
pub struct MyComplexContent2Type {
pub content: MyComplexContent2TypeContent,
}
pub enum MyComplexContent2TypeContent {
ElementC(BooleanType),
Content3(Option<MyComplexContent3Type>),
Content4(MyComplexContent4Type),
}
pub type BooleanType = bool;
pub struct MyComplexContent3Type {
pub element_d: StringType,
pub element_e: IntType,
}
pub struct MyComplexContent4Type {
pub element_f: StringType,
pub element_g: Vec<IntType>,
}
With this optimization the following code is generated:
pub struct MyComplexType {
pub element_a: Vec<String>,
pub element_b: Vec<i32>,
pub content_2: MyComplexContent2Type,
}
pub struct MyComplexContent2Type {
pub content: MyComplexContent2TypeContent,
}
pub enum MyComplexContent2TypeContent {
ElementC(bool),
Content3(Option<MyComplexContent3Type>),
Content4(MyComplexContent4Type),
}
pub struct MyComplexContent3Type {
pub element_d: String,
pub element_e: i32,
}
pub struct MyComplexContent4Type {
pub element_f: String,
pub element_g: Vec<i32>,
}
Source§impl Optimizer
impl Optimizer
Sourcepub fn use_unrestricted_base_type(self) -> Self
pub fn use_unrestricted_base_type(self) -> Self
This will use the unrestricted base type instead the restricted version when ever possible.
This is useful if you want to reduce the amount of different types, because the base type can store the same data than the restricted one. However this is only useful if you want to deserialize the type only. Using this feature for serializing types will cause problems because the type information is dropped during deserialization.
§Examples
Consider the following XML schema.
<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:tns="http://example.com"
targetNamespace="http://example.com">
<xs:complexType name="BaseType">
<xs:sequence>
<xs:element minOccurs="0" maxOccurs="unbounded" name="a" type="xs:string" />
<xs:element minOccurs="0" maxOccurs="unbounded" name="b" type="xs:int" />
</xs:sequence>
</xs:complexType>
<xs:complexType name="FirstRestrictedType">
<xs:complexContent>
<xs:restriction base="tns:BaseType">
<xs:sequence>
<xs:element minOccurs="1" maxOccurs="1" name="a" type="xs:string" />
</xs:sequence>
</xs:restriction>
</xs:complexContent>
</xs:complexType>
<xs:complexType name="SecondRestrictedType">
<xs:complexContent>
<xs:restriction base="tns:BaseType">
<xs:sequence>
<xs:element minOccurs="1" maxOccurs="unbounded" name="b" type="xs:int" />
</xs:sequence>
</xs:restriction>
</xs:complexContent>
</xs:complexType>
<xs:complexType name="ThirdRestrictedType">
<xs:complexContent>
<xs:restriction base="tns:SecondRestrictedType">
<xs:sequence>
<xs:element minOccurs="1" maxOccurs="1" name="b" type="xs:int" />
</xs:sequence>
</xs:restriction>
</xs:complexContent>
</xs:complexType>
</xs:schema>
Without this optimization this will result in the following code:
pub struct FirstRestrictedType {
pub a: String,
}
pub struct SecondRestrictedType {
pub b: Vec<i32>,
}
pub struct ThirdRestrictedType {
pub b: i32,
}
With this optimization the following code is generated:
pub type FirstRestrictedType = BaseType;
pub struct BaseType {
pub a: Vec<String>,
pub b: Vec<i32>,
}
pub type SecondRestrictedType = BaseType;
pub type ThirdRestrictedType = BaseType;