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;
10
11use std::collections::BTreeMap;
12use std::ops::Deref;
13use std::ops::DerefMut;
14
15pub use self::custom::CustomType;
16pub use self::helper::{VecHelper, WithIdent};
17pub use self::ident::{Ident, IdentType};
18pub use self::info::{
19    AnyAttributeInfo, AnyInfo, AttributeInfo, AttributesInfo, Base, ComplexInfo, DynamicInfo,
20    ElementInfo, ElementMode, ElementsInfo, EnumerationInfo, GroupInfo, ReferenceInfo, UnionInfo,
21    UnionTypeInfo, UnionTypesInfo, VariantInfo,
22};
23pub use self::name::Name;
24pub use self::type_::{BuildInInfo, Type, TypeEq};
25
26use crate::schema::{Namespace, NamespaceId};
27
28/// This structure contains information about the type and module definitions.
29///
30/// It is created by the [`Interpreter`](crate::interpreter::Interpreter) by reading
31/// the data of a specific [`Schemas`](crate::schema::Schemas). The types of this
32/// structure can be optimized further using the [`Optimizer`](crate::optimizer::Optimizer).
33#[derive(Default, Debug)]
34pub struct Types {
35    /// Map of the different types.
36    pub types: BTreeMap<Ident, Type>,
37
38    /// Map of the different namespaces.
39    pub modules: BTreeMap<NamespaceId, Module>,
40
41    next_name_id: usize,
42}
43
44/// Represents a module used by type information in the [`Types`] structure.
45#[derive(Debug)]
46pub struct Module {
47    /// Name of the module (also used as xml prefix).
48    pub name: Option<Name>,
49
50    /// Namespace of the module.
51    pub namespace: Option<Namespace>,
52}
53
54impl Types {
55    /// Create a new [`Name::Unnamed`] name by using a unique io for this name.
56    pub fn make_unnamed(&mut self) -> Name {
57        self.next_name_id = self.next_name_id.wrapping_add(1);
58
59        Name::Unnamed {
60            id: self.next_name_id,
61            ext: None,
62        }
63    }
64
65    /// Get the type of the passed `ident` with all single 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 Type> {
72        let mut visit = Vec::new();
73
74        get_resolved(self, ident, &mut visit).map(|(_ident, ty)| ty)
75    }
76}
77
78impl Deref for Types {
79    type Target = BTreeMap<Ident, Type>;
80
81    fn deref(&self) -> &Self::Target {
82        &self.types
83    }
84}
85
86impl DerefMut for Types {
87    fn deref_mut(&mut self) -> &mut Self::Target {
88        &mut self.types
89    }
90}
91
92pub(crate) fn get_resolved<'a>(
93    types: &'a Types,
94    ident: &'a Ident,
95    visited: &mut Vec<&'a Ident>,
96) -> Option<(&'a Ident, &'a Type)> {
97    if visited.contains(&ident) {
98        let chain = visited
99            .iter()
100            .map(ToString::to_string)
101            .chain(Some(ident.to_string()))
102            .collect::<Vec<_>>()
103            .join(" >> ");
104
105        tracing::debug!("Detected type reference loop: {chain}");
106
107        return None;
108    }
109
110    let ty = types.get(ident)?;
111
112    match ty {
113        Type::Reference(x) if x.is_single() => {
114            visited.push(ident);
115
116            let ret = match get_resolved(types, &x.type_, visited) {
117                None => Some((ident, ty)),
118                Some((ident, ty)) => Some((ident, ty)),
119            };
120
121            visited.pop();
122
123            ret
124        }
125        _ => Some((ident, ty)),
126    }
127}