1use std::fmt::{Debug, Display, Formatter, Result as FmtResult};
4use std::hash::{Hash, Hasher};
5use std::ops::{Deref, DerefMut};
6
7use super::{
8 ComplexInfo, CustomType, DynamicInfo, EnumerationInfo, GroupInfo, ReferenceInfo, Types,
9 UnionInfo,
10};
11
12#[derive(Debug, Clone)]
14pub struct Type {
15 pub display_name: Option<String>,
17
18 pub variant: TypeVariant,
20}
21
22#[derive(Debug, Clone)]
24pub enum TypeVariant {
25 Union(UnionInfo),
27
28 BuildIn(BuildInInfo),
30
31 Reference(ReferenceInfo),
33
34 Enumeration(EnumerationInfo),
36
37 Dynamic(DynamicInfo),
39
40 All(GroupInfo),
42
43 Choice(GroupInfo),
45
46 Sequence(GroupInfo),
48
49 ComplexType(ComplexInfo),
51}
52
53pub trait TypeEq: Sized {
60 fn type_hash<H: Hasher>(&self, hasher: &mut H, types: &Types);
62
63 fn type_hash_slice<H: Hasher>(slice: &[Self], hasher: &mut H, types: &Types) {
65 hasher.write_usize(slice.len());
66 for item in slice {
67 item.type_hash(hasher, types);
68 }
69 }
70
71 fn type_eq(&self, other: &Self, types: &Types) -> bool;
74
75 fn type_eq_iter<'a, X, Y>(x: X, y: Y, types: &Types) -> bool
77 where
78 Self: 'a,
79 X: IntoIterator<Item = &'a Self>,
80 Y: IntoIterator<Item = &'a Self>,
81 {
82 let mut x = x.into_iter();
83 let mut y = y.into_iter();
84
85 loop {
86 match (x.next(), y.next()) {
87 (None, None) => return true,
88 (Some(x), Some(y)) => {
89 if !x.type_eq(y, types) {
90 return false;
91 }
92 }
93 (_, _) => return false,
94 }
95 }
96 }
97}
98
99#[allow(missing_docs)]
102#[derive(Debug, Clone, Eq, PartialEq, Hash)]
103pub enum BuildInInfo {
104 U8,
105 U16,
106 U32,
107 U64,
108 U128,
109 Usize,
110
111 I8,
112 I16,
113 I32,
114 I64,
115 I128,
116 Isize,
117
118 F32,
119 F64,
120
121 Bool,
122 String,
123
124 Custom(CustomType),
125}
126
127macro_rules! impl_from {
130 ($var:ident, $ty:ty) => {
131 impl From<$ty> for Type {
132 fn from(value: $ty) -> Self {
133 Type::new(TypeVariant::$var(value))
134 }
135 }
136 };
137}
138
139impl_from!(Reference, ReferenceInfo);
140impl_from!(BuildIn, BuildInInfo);
141impl_from!(Enumeration, EnumerationInfo);
142impl_from!(Dynamic, DynamicInfo);
143impl_from!(ComplexType, ComplexInfo);
144
145impl Type {
146 #[must_use]
148 pub fn new(variant: TypeVariant) -> Self {
149 Self {
150 variant,
151 display_name: None,
152 }
153 }
154}
155
156impl Deref for Type {
157 type Target = TypeVariant;
158
159 fn deref(&self) -> &Self::Target {
160 &self.variant
161 }
162}
163
164impl DerefMut for Type {
165 fn deref_mut(&mut self) -> &mut Self::Target {
166 &mut self.variant
167 }
168}
169
170impl TypeEq for Type {
171 fn type_hash<H: Hasher>(&self, hasher: &mut H, types: &Types) {
172 #[allow(clippy::enum_glob_use)]
173 use TypeVariant::*;
174
175 self.display_name.hash(hasher);
176
177 match &self.variant {
178 Union(x) => x.type_hash(hasher, types),
179 BuildIn(x) => x.hash(hasher),
180 Reference(x) => x.type_hash(hasher, types),
181 Enumeration(x) => x.type_hash(hasher, types),
182 Dynamic(x) => x.type_hash(hasher, types),
183 All(x) => x.type_hash(hasher, types),
184 Choice(x) => x.type_hash(hasher, types),
185 Sequence(x) => x.type_hash(hasher, types),
186 ComplexType(x) => x.type_hash(hasher, types),
187 }
188 }
189
190 fn type_eq(&self, other: &Self, types: &Types) -> bool {
191 #[allow(clippy::enum_glob_use)]
192 use TypeVariant::*;
193
194 if self.display_name != other.display_name {
195 return false;
196 }
197
198 match (&self.variant, &other.variant) {
199 (Union(x), Union(y)) => x.type_eq(y, types),
200 (BuildIn(x), BuildIn(y)) => x == y,
201 (Reference(x), Reference(y)) => x.type_eq(y, types),
202 (Enumeration(x), Enumeration(y)) => x.type_eq(y, types),
203 (Dynamic(x), Dynamic(y)) => x.type_eq(y, types),
204 (All(x), All(y)) => x.type_eq(y, types),
205 (Choice(x), Choice(y)) => x.type_eq(y, types),
206 (Sequence(x), Sequence(y)) => x.type_eq(y, types),
207 (ComplexType(x), ComplexType(y)) => x.type_eq(y, types),
208 (_, _) => false,
209 }
210 }
211}
212
213impl BuildInInfo {
216 #[must_use]
218 pub fn as_str(&self) -> &'static str {
219 match self {
220 Self::U8 => "u8",
221 Self::U16 => "u16",
222 Self::U32 => "u32",
223 Self::U64 => "u64",
224 Self::U128 => "u128",
225 Self::Usize => "usize",
226
227 Self::I8 => "i8",
228 Self::I16 => "i16",
229 Self::I32 => "i32",
230 Self::I64 => "i64",
231 Self::I128 => "i128",
232 Self::Isize => "isize",
233
234 Self::F32 => "f32",
235 Self::F64 => "f64",
236
237 Self::Bool => "bool",
238 Self::String => "String",
239
240 Self::Custom(x) => x.name(),
241 }
242 }
243}
244
245impl Display for BuildInInfo {
246 fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult {
247 write!(f, "{}", self.as_str())
248 }
249}
250
251impl<T> TypeEq for Option<T>
254where
255 T: TypeEq,
256{
257 fn type_hash<H: Hasher>(&self, hasher: &mut H, types: &Types) {
258 if let Some(inner) = self {
259 hasher.write_u8(1);
260 inner.type_hash(hasher, types);
261 } else {
262 hasher.write_u8(0);
263 }
264 }
265
266 fn type_eq(&self, other: &Self, types: &Types) -> bool {
267 match (self, other) {
268 (Some(x), Some(y)) => x.type_eq(y, types),
269 (None, None) => true,
270 (_, _) => false,
271 }
272 }
273}