xsd_parser/types/
mod.rs

1//! The `types` module contains all type information related types.
2
3pub mod custom;
4pub mod ident;
5pub mod info;
6pub mod name;
7pub mod type_;
8
9mod helper;
10mod name_builder;
11
12use std::collections::BTreeMap;
13use std::ops::Deref;
14use std::ops::DerefMut;
15use std::sync::atomic::AtomicUsize;
16use std::sync::Arc;
17
18pub use self::custom::CustomType;
19pub use self::helper::{VecHelper, WithIdent};
20pub use self::ident::{Ident, IdentType};
21pub use self::info::{
22    AnyAttributeInfo, AnyInfo, AttributeInfo, AttributesInfo, Base, ComplexInfo, DynamicInfo,
23    ElementInfo, ElementMode, ElementsInfo, EnumerationInfo, GroupInfo, ReferenceInfo, UnionInfo,
24    UnionTypeInfo, UnionTypesInfo, VariantInfo,
25};
26pub use self::name::Name;
27pub use self::name_builder::{NameBuilder, NameFallback};
28pub use self::type_::{BuildInInfo, Type, TypeEq, TypeVariant};
29
30use crate::schema::{Namespace, NamespaceId};
31
32/// This structure contains information about the type and module definitions.
33///
34/// It is created by the [`Interpreter`](crate::interpreter::Interpreter) by reading
35/// the data of a specific [`Schemas`](crate::schema::Schemas). The types of this
36/// structure can be optimized further using the [`Optimizer`](crate::optimizer::Optimizer).
37#[derive(Default, Debug)]
38pub struct Types {
39    /// Map of the different types.
40    pub types: BTreeMap<Ident, Type>,
41
42    /// Map of the different namespaces.
43    pub modules: BTreeMap<NamespaceId, Module>,
44
45    next_name_id: Arc<AtomicUsize>,
46}
47
48/// Represents a module used by type information in the [`Types`] structure.
49#[derive(Debug)]
50pub struct Module {
51    /// Name of the module (also used as xml prefix).
52    pub name: Option<Name>,
53
54    /// Namespace of the module.
55    pub namespace: Option<Namespace>,
56}
57
58impl Types {
59    /// Create a new [`NameBuilder`] instance, that can be used to build type named.
60    pub fn name_builder(&mut self) -> NameBuilder {
61        NameBuilder::new(self.next_name_id.clone())
62    }
63
64    /// Get the identifier and the type of the passed `ident` with all single
65    /// type references resolved.
66    ///
67    /// Tries to find the type specified by the passed `ident` and resolve simple
68    /// type definitions to the very base type. If the type could not be found `None`
69    /// is returned.
70    #[must_use]
71    pub fn get_resolved<'a>(&'a self, ident: &'a Ident) -> Option<(&'a Ident, &'a Type)> {
72        let mut visit = Vec::new();
73
74        get_resolved_impl(self, ident, &mut visit)
75    }
76
77    /// Get the type of the passed `ident` with all single type references resolved.
78    ///
79    /// Like [`get_resolved`](Self::get_resolved), but instead of returning the identifier and
80    /// the type it will return only the resolved type.
81    #[must_use]
82    pub fn get_resolved_type<'a>(&'a self, ident: &'a Ident) -> Option<&'a Type> {
83        self.get_resolved(ident).map(|(_ident, ty)| ty)
84    }
85
86    /// Get the type ident of the passed `ident` with all single type references resolved.
87    ///
88    /// Like [`get_resolved`](Self::get_resolved), but instead of returning the identifier and
89    /// the type it will return only the identifier of the resolved type.
90    #[must_use]
91    pub fn get_resolved_ident<'a>(&'a self, ident: &'a Ident) -> Option<&'a Ident> {
92        self.get_resolved(ident).map(|(ident, _ty)| ident)
93    }
94
95    /// Return the [`TypeVariant`] of corresponding type for the passed identifier.
96    ///
97    /// This is a shorthand for `self.get(ident).map(|ty| &type.variant)`.
98    #[inline]
99    #[must_use]
100    pub fn get_variant(&self, ident: &Ident) -> Option<&TypeVariant> {
101        self.get(ident).map(|ty| &ty.variant)
102    }
103
104    /// Return the [`TypeVariant`] of corresponding type for the passed identifier.
105    ///
106    /// This is a shorthand for `self.get_mut(ident).map(|ty| &type.variant)`.
107    #[inline]
108    #[must_use]
109    pub fn get_variant_mut(&mut self, ident: &Ident) -> Option<&mut TypeVariant> {
110        self.get_mut(ident).map(|ty| &mut ty.variant)
111    }
112}
113
114impl Deref for Types {
115    type Target = BTreeMap<Ident, Type>;
116
117    fn deref(&self) -> &Self::Target {
118        &self.types
119    }
120}
121
122impl DerefMut for Types {
123    fn deref_mut(&mut self) -> &mut Self::Target {
124        &mut self.types
125    }
126}
127
128fn get_resolved_impl<'a>(
129    types: &'a Types,
130    ident: &'a Ident,
131    visited: &mut Vec<&'a Ident>,
132) -> Option<(&'a Ident, &'a Type)> {
133    if visited.contains(&ident) {
134        let chain = visited
135            .iter()
136            .map(ToString::to_string)
137            .chain(Some(ident.to_string()))
138            .collect::<Vec<_>>()
139            .join(" >> ");
140
141        tracing::debug!("Detected type reference loop: {chain}");
142
143        return None;
144    }
145
146    let ty = types.get(ident)?;
147
148    match &ty.variant {
149        TypeVariant::Reference(x) if x.is_single() => {
150            visited.push(ident);
151
152            let ret = match get_resolved_impl(types, &x.type_, visited) {
153                None => Some((ident, ty)),
154                Some((ident, ty)) => Some((ident, ty)),
155            };
156
157            visited.pop();
158
159            ret
160        }
161        _ => Some((ident, ty)),
162    }
163}