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