xsd_parser/types/
ident.rs

1//! Contains the [`Ident`] helper type and all related types.
2
3use std::fmt::{Display, Formatter, Result as FmtResult};
4use std::hash::{Hash, Hasher};
5
6use crate::schema::NamespaceId;
7
8use super::{get_resolved, Name, TypeEq, Types};
9
10/// Represents a type identifier.
11#[derive(Debug, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
12pub struct Ident {
13    /// Namespace the type is defined in
14    pub ns: Option<NamespaceId>,
15
16    /// Name of the type.
17    pub name: Name,
18
19    /// Type of the identifier (because pure names are not unique in XSD).
20    pub type_: IdentType,
21}
22
23/// Type of the identifier.
24#[derive(Debug, Clone, Copy, Eq, PartialEq, Ord, PartialOrd, Hash)]
25pub enum IdentType {
26    /// Used for `xs:simpleType` or `xs:complexType`.
27    Type = 0,
28
29    /// Used for `xs:group`.
30    Group = 1,
31
32    /// Used for `xs:element`.
33    Element = 2,
34
35    /// Used for inline types of `xs:element`.
36    ElementType = 3,
37
38    /// Used for `xs:attribute`.
39    Attribute = 4,
40
41    /// Used for `xs:attributeGroup`.
42    AttributeGroup = 5,
43
44    /// Used for build-in types.
45    BuildIn = 6,
46
47    /// Used for `xs:enumeration`.
48    Enumeration = 7,
49}
50
51#[allow(missing_docs)]
52impl Ident {
53    pub const U8: Self = Self::build_in("u8");
54    pub const U16: Self = Self::build_in("u16");
55    pub const U32: Self = Self::build_in("u32");
56    pub const U64: Self = Self::build_in("u64");
57    pub const U128: Self = Self::build_in("u128");
58    pub const USIZE: Self = Self::build_in("usize");
59
60    pub const I8: Self = Self::build_in("i8");
61    pub const I16: Self = Self::build_in("i16");
62    pub const I32: Self = Self::build_in("i32");
63    pub const I64: Self = Self::build_in("i64");
64    pub const I128: Self = Self::build_in("i128");
65    pub const ISIZE: Self = Self::build_in("isize");
66
67    pub const F32: Self = Self::build_in("f32");
68    pub const F64: Self = Self::build_in("f64");
69
70    pub const BOOL: Self = Self::build_in("bool");
71    pub const STRING: Self = Self::build_in("String");
72
73    pub const ANY_TYPE: Self = Self::type_("anyType");
74
75    pub const BUILD_IN: &[Self] = &[
76        Self::U8,
77        Self::U16,
78        Self::U32,
79        Self::U64,
80        Self::U128,
81        Self::USIZE,
82        Self::I8,
83        Self::I16,
84        Self::I32,
85        Self::I64,
86        Self::I128,
87        Self::ISIZE,
88        Self::F32,
89        Self::F64,
90        Self::BOOL,
91        Self::STRING,
92    ];
93}
94
95impl Ident {
96    /// Create an [`Type`](IdentType::Type) [`Ident`]ifier with the given `name`.
97    #[must_use]
98    pub fn new(name: Name) -> Self {
99        Self {
100            ns: None,
101            name,
102            type_: IdentType::Type,
103        }
104    }
105
106    /// Create an [`Type`](IdentType::Type) [`Ident`]ifier with the given `name`.
107    #[must_use]
108    pub const fn type_(name: &'static str) -> Self {
109        Self {
110            ns: None,
111            name: Name::named(name),
112            type_: IdentType::Type,
113        }
114    }
115
116    /// Create an [`BuildIn`](IdentType::BuildIn) [`Ident`]ifier with the given `name`.
117    #[must_use]
118    pub const fn build_in(name: &'static str) -> Self {
119        Self {
120            ns: None,
121            name: Name::named(name),
122            type_: IdentType::BuildIn,
123        }
124    }
125
126    /// Create an [`Element`](IdentType::Element) [`Ident`]ifier with the given `name`.
127    #[must_use]
128    pub const fn element(name: &'static str) -> Self {
129        Self {
130            ns: None,
131            name: Name::named(name),
132            type_: IdentType::Element,
133        }
134    }
135
136    /// Set the namespace of the identifier.
137    #[must_use]
138    pub fn with_ns(mut self, ns: Option<NamespaceId>) -> Self {
139        self.ns = ns;
140
141        self
142    }
143
144    /// Set the type of the identifier.
145    #[must_use]
146    pub fn with_type(mut self, type_: IdentType) -> Self {
147        self.type_ = type_;
148
149        self
150    }
151
152    /// Returns `true` if this is build-in type of the rust language, `false` otherwise.
153    #[must_use]
154    pub fn is_build_in(&self) -> bool {
155        Ident::BUILD_IN.contains(self)
156    }
157}
158
159impl Display for Ident {
160    fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult {
161        let Self { ns, name, type_ } = self;
162
163        match type_ {
164            IdentType::Type => write!(f, "Type(")?,
165            IdentType::Group => write!(f, "Group(")?,
166            IdentType::BuildIn => write!(f, "BuildIn(")?,
167            IdentType::Element => write!(f, "Element(")?,
168            IdentType::ElementType => write!(f, "ElementType(")?,
169            IdentType::Attribute => write!(f, "Attribute(")?,
170            IdentType::AttributeGroup => write!(f, "AttributeGroup(")?,
171            IdentType::Enumeration => write!(f, "Enumeration(")?,
172        }
173
174        if f.sign_minus() {
175            write!(f, "{name})")?;
176        } else if let Some(ns) = ns {
177            write!(f, "ns={}, name={name})", ns.0)?;
178        } else {
179            write!(f, "ns=default, name={name})")?;
180        }
181
182        Ok(())
183    }
184}
185
186impl TypeEq for Ident {
187    fn type_hash<H: Hasher>(&self, hasher: &mut H, types: &Types) {
188        let mut visit = Vec::new();
189
190        get_resolved(types, self, &mut visit)
191            .map_or(self, |(ident, _ty)| ident)
192            .hash(hasher);
193    }
194
195    fn type_eq(&self, other: &Self, types: &Types) -> bool {
196        let a = {
197            let mut visit = Vec::new();
198
199            get_resolved(types, self, &mut visit).map(|(ident, _ty)| ident)
200        };
201
202        let b = {
203            let mut visit = Vec::new();
204
205            get_resolved(types, other, &mut visit).map(|(ident, _ty)| ident)
206        };
207
208        a == b
209    }
210}