Skip to main content

xsd_parser/models/
ident.rs

1//! Defines the [`TypeIdent`] and [`NodeIdent`] type and all related helper types.
2
3use std::fmt::{Display, Formatter, Result as FmtResult};
4use std::hash::Hash;
5
6use crate::models::schema::{NamespaceId, SchemaId};
7
8use super::Name;
9
10/// Type that is used to identify types in the schema definition.
11#[derive(Debug, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
12pub struct TypeIdent {
13    /// Namespace the type is defined in
14    pub ns: NamespaceId,
15
16    /// Id of the schema file the type pointed to by this identifier was defined
17    /// at.
18    ///
19    /// This is needed to support the case when identifier are duplicated across
20    /// schema files, or redefined by `xs:redefine` or `xs:override`.
21    pub schema: SchemaId,
22
23    /// Name of the type.
24    pub name: Name,
25
26    /// Type of the identifier (because pure names are not unique in XSD).
27    pub type_: TypeIdentType,
28}
29
30/// Defines the type of the [`TypeIdent`].
31pub type TypeIdentType = IdentType;
32
33/// Type that is used to identify properties (elements, attributes, enumerations, ...)
34/// in the schema definition.
35#[derive(Debug, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
36pub struct PropertyIdent {
37    /// Namespace the type is defined in
38    pub ns: NamespaceId,
39
40    /// Name of the type.
41    pub name: Name,
42}
43
44/// Identifier used to identify elements in the
45/// [`ElementsMeta`](crate::models::meta::ElementsMeta) structure.
46pub type ElementIdent = PropertyIdent;
47
48/// Identifier used to identify attributes in the
49/// [`AttributesMeta`](crate::models::meta::AttributesMeta) structure.
50pub type AttributeIdent = PropertyIdent;
51
52/// Identifier used to identify enumerations in the
53/// [`EnumerationMetaVariants`](crate::models::meta::EnumerationMetaVariants)
54/// structure.
55pub type EnumerationIdent = PropertyIdent;
56
57/// Type of the identifier.
58#[derive(Debug, Clone, Copy, Eq, PartialEq, Ord, PartialOrd, Hash)]
59pub enum IdentType {
60    /// Used for `xs:simpleType` or `xs:complexType`.
61    Type = 0,
62
63    /// Used for `xs:group`.
64    Group = 1,
65
66    /// Used for `xs:element`.
67    Element = 2,
68
69    /// Used for inline types of `xs:element`.
70    ElementType = 3,
71
72    /// Used for `xs:attribute`.
73    Attribute = 4,
74
75    /// Used for `xs:attributeGroup`.
76    AttributeGroup = 5,
77
78    /// Used for build-in types.
79    BuildIn = 6,
80
81    /// Used for `xs:enumeration`.
82    Enumeration = 7,
83
84    /// Used to define the content for [`Nillable`](xsd_parser_types::xml::Nillable) types.
85    NillableContent = 8,
86
87    /// One concrete element in a substitution group.
88    DynamicElement = 9,
89}
90
91/* TypeIdent */
92
93#[allow(missing_docs)]
94impl TypeIdent {
95    pub const UNKNOWN: Self = Self::type_("UNKNOWN");
96
97    pub const U8: Self = Self::build_in("u8");
98    pub const U16: Self = Self::build_in("u16");
99    pub const U32: Self = Self::build_in("u32");
100    pub const U64: Self = Self::build_in("u64");
101    pub const U128: Self = Self::build_in("u128");
102    pub const USIZE: Self = Self::build_in("usize");
103
104    pub const I8: Self = Self::build_in("i8");
105    pub const I16: Self = Self::build_in("i16");
106    pub const I32: Self = Self::build_in("i32");
107    pub const I64: Self = Self::build_in("i64");
108    pub const I128: Self = Self::build_in("i128");
109    pub const ISIZE: Self = Self::build_in("isize");
110
111    pub const F32: Self = Self::build_in("f32");
112    pub const F64: Self = Self::build_in("f64");
113
114    pub const BOOL: Self = Self::build_in("bool");
115    pub const STR: Self = Self::build_in("str");
116    pub const STRING: Self = Self::build_in("String");
117
118    pub const ANY_TYPE: Self = Self::type_("anyType");
119
120    pub const BUILD_IN: &[Self] = &[
121        Self::U8,
122        Self::U16,
123        Self::U32,
124        Self::U64,
125        Self::U128,
126        Self::USIZE,
127        Self::I8,
128        Self::I16,
129        Self::I32,
130        Self::I64,
131        Self::I128,
132        Self::ISIZE,
133        Self::F32,
134        Self::F64,
135        Self::BOOL,
136        Self::STR,
137        Self::STRING,
138    ];
139}
140
141impl TypeIdent {
142    /// Create a new [`TypeIdent`] instance with [`IdentType::Type`] and the passed `name`.
143    #[must_use]
144    pub const fn new(name: Name) -> Self {
145        Self {
146            ns: NamespaceId::UNKNOWN,
147            schema: SchemaId::UNKNOWN,
148            name,
149            type_: IdentType::Type,
150        }
151    }
152
153    /// Create a new [`TypeIdent`] instance with [`IdentType::Type`] and the passed `name`.
154    #[must_use]
155    pub const fn type_(name: &'static str) -> Self {
156        Self {
157            ns: NamespaceId::UNKNOWN,
158            schema: SchemaId::UNKNOWN,
159            name: Name::named(name),
160            type_: IdentType::Type,
161        }
162    }
163
164    /// Create a new [`TypeIdent`] instance with [`IdentType::BuildIn`] and the passed `name`.
165    #[must_use]
166    pub const fn build_in(name: &'static str) -> Self {
167        Self {
168            ns: NamespaceId::ANONYMOUS,
169            schema: SchemaId::UNKNOWN,
170            name: Name::named(name),
171            type_: IdentType::BuildIn,
172        }
173    }
174
175    /// Create a new [`TypeIdent`] instance with [`IdentType::Element`] and the passed `name`.
176    #[must_use]
177    pub const fn element(name: &'static str) -> Self {
178        Self {
179            ns: NamespaceId::UNKNOWN,
180            schema: SchemaId::UNKNOWN,
181            name: Name::named(name),
182            type_: IdentType::Element,
183        }
184    }
185
186    /// Change the [`NamespaceId`] of this type identifier.
187    #[must_use]
188    pub fn with_ns(mut self, ns: NamespaceId) -> Self {
189        self.ns = ns;
190
191        self
192    }
193
194    /// Change the [`SchemaId`] of this type identifier.
195    #[must_use]
196    pub fn with_schema(mut self, schema: SchemaId) -> Self {
197        self.schema = schema;
198
199        self
200    }
201
202    /// Change the [`Name`] of this type identifier.
203    #[must_use]
204    pub fn with_name(mut self, name: Name) -> Self {
205        self.name = name;
206
207        self
208    }
209
210    /// Change the [`TypeIdentType`] of this type identifier.
211    #[must_use]
212    pub fn with_type(mut self, type_: TypeIdentType) -> Self {
213        self.type_ = type_;
214
215        self
216    }
217
218    /// Returns `true` if the passed identifier matches the current one.
219    ///
220    /// This ignores the values stored in [`ns`](TypeIdent::ns) and
221    /// [`schema`](TypeIdent::schema) if they are set to `UNKNOWN`.
222    #[must_use]
223    pub fn matches(&self, other: &Self) -> bool {
224        let Self {
225            ns,
226            schema,
227            name,
228            type_,
229        } = self;
230
231        (ns.is_unknown() || other.ns.is_unknown() || ns.eq(&other.ns))
232            && (schema.is_unknown() || other.schema.is_unknown() || schema.eq(&other.schema))
233            && name.eq(&other.name)
234            && type_.eq(&other.type_)
235    }
236
237    /// Convert this type identifier into a [`PropertyIdent`] by dropping the schema
238    /// and type information.
239    #[must_use]
240    pub fn to_property_ident(&self) -> PropertyIdent {
241        let Self {
242            ns,
243            schema: _,
244            name,
245            type_: _,
246        } = self;
247
248        PropertyIdent {
249            ns: *ns,
250            name: name.clone(),
251        }
252    }
253
254    /// Returns `true` if this is build-in type of the rust language, `false` otherwise.
255    #[must_use]
256    pub fn is_build_in(&self) -> bool {
257        TypeIdent::BUILD_IN.contains(self)
258    }
259
260    /// Returns `true` if this identifier is fully qualified, `false` otherwise.
261    ///
262    /// The identifier is fully qualified, if neither the [`ns`](TypeIdent::ns),
263    /// nor the [`schema`](TypeIdent::schema) is set to `UNKNOWN`.
264    #[must_use]
265    pub fn is_fully_qualified(&self) -> bool {
266        !self.ns.is_unknown() && !self.schema.is_unknown()
267    }
268}
269
270impl Display for TypeIdent {
271    fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult {
272        fmt_ident(
273            f,
274            Some(self.ns),
275            Some(self.schema),
276            &self.name,
277            Some(self.type_),
278        )
279    }
280}
281
282/* PropertyIdent */
283
284impl PropertyIdent {
285    /// Create a new [`PropertyIdent`] instance with the passed `name`.
286    #[inline]
287    #[must_use]
288    pub const fn new(name: Name) -> Self {
289        Self {
290            ns: NamespaceId::UNKNOWN,
291            name,
292        }
293    }
294
295    /// Create a new [`PropertyIdent`] instance with the passed `name`.
296    #[inline]
297    #[must_use]
298    pub const fn named(name: &'static str) -> Self {
299        Self {
300            ns: NamespaceId::UNKNOWN,
301            name: Name::named(name),
302        }
303    }
304
305    /// Change the [`NamespaceId`] of this identifier.
306    #[inline]
307    #[must_use]
308    pub fn with_ns(mut self, ns: NamespaceId) -> Self {
309        self.ns = ns;
310
311        self
312    }
313}
314
315impl Display for PropertyIdent {
316    fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult {
317        fmt_ident(f, Some(self.ns), None, &self.name, None)
318    }
319}
320
321fn fmt_ident(
322    f: &mut Formatter<'_>,
323    ns: Option<NamespaceId>,
324    schema: Option<SchemaId>,
325    name: &Name,
326    type_: Option<IdentType>,
327) -> FmtResult {
328    match type_ {
329        None => write!(f, "Ident(")?,
330        Some(IdentType::Type) => write!(f, "Type(")?,
331        Some(IdentType::Group) => write!(f, "Group(")?,
332        Some(IdentType::BuildIn) => write!(f, "BuildIn(")?,
333        Some(IdentType::Element) => write!(f, "Element(")?,
334        Some(IdentType::ElementType) => write!(f, "ElementType(")?,
335        Some(IdentType::Attribute) => write!(f, "Attribute(")?,
336        Some(IdentType::AttributeGroup) => write!(f, "AttributeGroup(")?,
337        Some(IdentType::Enumeration) => write!(f, "Enumeration(")?,
338        Some(IdentType::NillableContent) => write!(f, "NillableContent(")?,
339        Some(IdentType::DynamicElement) => write!(f, "DynamicElement(")?,
340    }
341
342    if f.sign_minus() {
343        write!(f, "{name})")?;
344    } else {
345        if let Some(SchemaId(schema)) = schema {
346            write!(f, "schema={schema}, ")?;
347        }
348
349        if let Some(ns) = ns {
350            write!(f, "ns={}, name={name})", ns.0)?;
351        } else {
352            write!(f, "ns=default, name={name})")?;
353        }
354    }
355
356    Ok(())
357}