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::{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    /// Create an [`Ident`]ifier suitable for field names with the given `name`.
137    #[must_use]
138    pub const fn name(name: &'static str) -> Self {
139        // We do not have a separate `IdentType` for fields, so we just use `IdentType::Type`
140        Self::type_(name)
141    }
142
143    /// Set the namespace of the identifier.
144    #[must_use]
145    pub fn with_ns(mut self, ns: Option<NamespaceId>) -> Self {
146        self.ns = ns;
147
148        self
149    }
150
151    /// Set the type of the identifier.
152    #[must_use]
153    pub fn with_type(mut self, type_: IdentType) -> Self {
154        self.type_ = type_;
155
156        self
157    }
158
159    /// Returns `true` if this is build-in type of the rust language, `false` otherwise.
160    #[must_use]
161    pub fn is_build_in(&self) -> bool {
162        Ident::BUILD_IN.contains(self)
163    }
164}
165
166impl Display for Ident {
167    fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult {
168        let Self { ns, name, type_ } = self;
169
170        match type_ {
171            IdentType::Type => write!(f, "Type(")?,
172            IdentType::Group => write!(f, "Group(")?,
173            IdentType::BuildIn => write!(f, "BuildIn(")?,
174            IdentType::Element => write!(f, "Element(")?,
175            IdentType::ElementType => write!(f, "ElementType(")?,
176            IdentType::Attribute => write!(f, "Attribute(")?,
177            IdentType::AttributeGroup => write!(f, "AttributeGroup(")?,
178            IdentType::Enumeration => write!(f, "Enumeration(")?,
179        }
180
181        if f.sign_minus() {
182            write!(f, "{name})")?;
183        } else if let Some(ns) = ns {
184            write!(f, "ns={}, name={name})", ns.0)?;
185        } else {
186            write!(f, "ns=default, name={name})")?;
187        }
188
189        Ok(())
190    }
191}
192
193impl TypeEq for Ident {
194    fn type_hash<H: Hasher>(&self, hasher: &mut H, types: &Types) {
195        types.get_resolved_ident(self).unwrap_or(self).hash(hasher);
196    }
197
198    fn type_eq(&self, other: &Self, types: &Types) -> bool {
199        let a = types.get_resolved_ident(self).unwrap_or(self);
200        let b = types.get_resolved_ident(other).unwrap_or(other);
201
202        a == b
203    }
204}