xsd_parser/types/
type_.rs

1//! Contains the [`Type`] type information and all related types.
2
3use std::fmt::{Debug, Display, Formatter, Result as FmtResult};
4use std::hash::{Hash, Hasher};
5
6use super::{
7    ComplexInfo, CustomType, DynamicInfo, EnumerationInfo, GroupInfo, ReferenceInfo, Types,
8    UnionInfo,
9};
10
11/// Represents a type that was read and interpreted from an XML schema.
12#[derive(Debug, Clone)]
13pub enum Type {
14    /// Represents a union type
15    Union(UnionInfo),
16
17    /// Represents a build-in type
18    BuildIn(BuildInInfo),
19
20    /// References an other type
21    Reference(ReferenceInfo),
22
23    /// Represents an enumeration
24    Enumeration(EnumerationInfo),
25
26    /// Represents an dynamic element
27    Dynamic(DynamicInfo),
28
29    /// Represents a specific set of elements
30    All(GroupInfo),
31
32    /// Represents a choice of different elements
33    Choice(GroupInfo),
34
35    /// Represents a sequence of different elements
36    Sequence(GroupInfo),
37
38    /// Represents a complex type
39    ComplexType(ComplexInfo),
40}
41
42/// Trait to check if two types are equal to each other or not.
43///
44/// This trait will automatically resolve type definitions to its target
45/// type before it compares the two instances. This means a type is considered
46/// as equal, if all type identifiers point to the same type and all normal
47/// values are equal.
48pub trait TypeEq: Sized {
49    /// Feeds this value into the given [`Hasher`].
50    fn type_hash<H: Hasher>(&self, hasher: &mut H, types: &Types);
51
52    /// Feeds a slice of this value into the given [`Hasher`].
53    fn type_hash_slice<H: Hasher>(slice: &[Self], hasher: &mut H, types: &Types) {
54        hasher.write_usize(slice.len());
55        for item in slice {
56            item.type_hash(hasher, types);
57        }
58    }
59
60    /// Check if this instance is equal to the `other` instance using the passed
61    /// `types` to resolve identifiers.
62    fn type_eq(&self, other: &Self, types: &Types) -> bool;
63
64    /// Check if the two passed iterators contain type equal elements.
65    fn type_eq_iter<'a, X, Y>(x: X, y: Y, types: &Types) -> bool
66    where
67        Self: 'a,
68        X: IntoIterator<Item = &'a Self>,
69        Y: IntoIterator<Item = &'a Self>,
70    {
71        let mut x = x.into_iter();
72        let mut y = y.into_iter();
73
74        loop {
75            match (x.next(), y.next()) {
76                (None, None) => return true,
77                (Some(x), Some(y)) => {
78                    if !x.type_eq(y, types) {
79                        return false;
80                    }
81                }
82                (_, _) => return false,
83            }
84        }
85    }
86}
87
88/// Union that defined the build in types of the rust language or
89/// custom defined types.
90#[allow(missing_docs)]
91#[derive(Debug, Clone, Eq, PartialEq, Hash)]
92pub enum BuildInInfo {
93    U8,
94    U16,
95    U32,
96    U64,
97    U128,
98    Usize,
99
100    I8,
101    I16,
102    I32,
103    I64,
104    I128,
105    Isize,
106
107    F32,
108    F64,
109
110    Bool,
111    String,
112
113    Custom(CustomType),
114}
115
116/* Type */
117
118macro_rules! impl_from {
119    ($var:ident, $ty:ty) => {
120        impl From<$ty> for Type {
121            fn from(value: $ty) -> Self {
122                Self::$var(value)
123            }
124        }
125    };
126}
127
128impl_from!(Reference, ReferenceInfo);
129impl_from!(BuildIn, BuildInInfo);
130impl_from!(Enumeration, EnumerationInfo);
131
132impl TypeEq for Type {
133    fn type_hash<H: Hasher>(&self, hasher: &mut H, types: &Types) {
134        #[allow(clippy::enum_glob_use)]
135        use Type::*;
136
137        match self {
138            Union(x) => x.type_hash(hasher, types),
139            BuildIn(x) => x.hash(hasher),
140            Reference(x) => x.type_hash(hasher, types),
141            Enumeration(x) => x.type_hash(hasher, types),
142            Dynamic(x) => x.type_hash(hasher, types),
143            All(x) => x.type_hash(hasher, types),
144            Choice(x) => x.type_hash(hasher, types),
145            Sequence(x) => x.type_hash(hasher, types),
146            ComplexType(x) => x.type_hash(hasher, types),
147        }
148    }
149
150    fn type_eq(&self, other: &Self, types: &Types) -> bool {
151        #[allow(clippy::enum_glob_use)]
152        use Type::*;
153
154        match (self, other) {
155            (Union(x), Union(y)) => x.type_eq(y, types),
156            (BuildIn(x), BuildIn(y)) => x == y,
157            (Reference(x), Reference(y)) => x.type_eq(y, types),
158            (Enumeration(x), Enumeration(y)) => x.type_eq(y, types),
159            (Dynamic(x), Dynamic(y)) => x.type_eq(y, types),
160            (All(x), All(y)) => x.type_eq(y, types),
161            (Choice(x), Choice(y)) => x.type_eq(y, types),
162            (Sequence(x), Sequence(y)) => x.type_eq(y, types),
163            (ComplexType(x), ComplexType(y)) => x.type_eq(y, types),
164            (_, _) => false,
165        }
166    }
167}
168
169/* BuildInInfo */
170
171impl BuildInInfo {
172    /// Get the name of the build-in type as `&str`.
173    #[must_use]
174    pub fn as_str(&self) -> &'static str {
175        match self {
176            Self::U8 => "u8",
177            Self::U16 => "u16",
178            Self::U32 => "u32",
179            Self::U64 => "u64",
180            Self::U128 => "u128",
181            Self::Usize => "usize",
182
183            Self::I8 => "i8",
184            Self::I16 => "i16",
185            Self::I32 => "i32",
186            Self::I64 => "i64",
187            Self::I128 => "i128",
188            Self::Isize => "isize",
189
190            Self::F32 => "f32",
191            Self::F64 => "f64",
192
193            Self::Bool => "bool",
194            Self::String => "String",
195
196            Self::Custom(x) => x.name(),
197        }
198    }
199}
200
201impl Display for BuildInInfo {
202    fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult {
203        write!(f, "{}", self.as_str())
204    }
205}
206
207/* TypeEq */
208
209impl<T> TypeEq for Option<T>
210where
211    T: TypeEq,
212{
213    fn type_hash<H: Hasher>(&self, hasher: &mut H, types: &Types) {
214        if let Some(inner) = self {
215            hasher.write_u8(1);
216            inner.type_hash(hasher, types);
217        } else {
218            hasher.write_u8(0);
219        }
220    }
221
222    fn type_eq(&self, other: &Self, types: &Types) -> bool {
223        match (self, other) {
224            (Some(x), Some(y)) => x.type_eq(y, types),
225            (None, None) => true,
226            (_, _) => false,
227        }
228    }
229}