1pub 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#[derive(Default, Debug)]
34pub struct Types {
35 pub types: BTreeMap<Ident, Type>,
37
38 pub modules: BTreeMap<NamespaceId, Module>,
40
41 next_name_id: usize,
42}
43
44#[derive(Debug)]
46pub struct Module {
47 pub name: Option<Name>,
49
50 pub namespace: Option<Namespace>,
52}
53
54impl Types {
55 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 #[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}