1use std::fmt::{Debug, Display, Formatter, Result as FmtResult};
4use std::hash::{Hash, Hasher};
5
6use super::{
7 ComplexInfo, CustomType, DynamicInfo, EnumerationInfo, GroupInfo, ReferenceInfo, Types,
8 UnionInfo,
9};
10
11#[derive(Debug, Clone)]
13pub enum Type {
14 Union(UnionInfo),
16
17 BuildIn(BuildInInfo),
19
20 Reference(ReferenceInfo),
22
23 Enumeration(EnumerationInfo),
25
26 Dynamic(DynamicInfo),
28
29 All(GroupInfo),
31
32 Choice(GroupInfo),
34
35 Sequence(GroupInfo),
37
38 ComplexType(ComplexInfo),
40}
41
42pub trait TypeEq: Sized {
49 fn type_hash<H: Hasher>(&self, hasher: &mut H, types: &Types);
51
52 fn type_hash_slice<H: Hasher>(slice: &[Self], hasher: &mut H, types: &Types) {
54 hasher.write_usize(slice.len());
55 for item in slice {
56 item.type_hash(hasher, types);
57 }
58 }
59
60 fn type_eq(&self, other: &Self, types: &Types) -> bool;
63
64 fn type_eq_iter<'a, X, Y>(x: X, y: Y, types: &Types) -> bool
66 where
67 Self: 'a,
68 X: IntoIterator<Item = &'a Self>,
69 Y: IntoIterator<Item = &'a Self>,
70 {
71 let mut x = x.into_iter();
72 let mut y = y.into_iter();
73
74 loop {
75 match (x.next(), y.next()) {
76 (None, None) => return true,
77 (Some(x), Some(y)) => {
78 if !x.type_eq(y, types) {
79 return false;
80 }
81 }
82 (_, _) => return false,
83 }
84 }
85 }
86}
87
88#[allow(missing_docs)]
91#[derive(Debug, Clone, Eq, PartialEq, Hash)]
92pub enum BuildInInfo {
93 U8,
94 U16,
95 U32,
96 U64,
97 U128,
98 Usize,
99
100 I8,
101 I16,
102 I32,
103 I64,
104 I128,
105 Isize,
106
107 F32,
108 F64,
109
110 Bool,
111 String,
112
113 Custom(CustomType),
114}
115
116macro_rules! impl_from {
119 ($var:ident, $ty:ty) => {
120 impl From<$ty> for Type {
121 fn from(value: $ty) -> Self {
122 Self::$var(value)
123 }
124 }
125 };
126}
127
128impl_from!(Reference, ReferenceInfo);
129impl_from!(BuildIn, BuildInInfo);
130impl_from!(Enumeration, EnumerationInfo);
131
132impl TypeEq for Type {
133 fn type_hash<H: Hasher>(&self, hasher: &mut H, types: &Types) {
134 #[allow(clippy::enum_glob_use)]
135 use Type::*;
136
137 match self {
138 Union(x) => x.type_hash(hasher, types),
139 BuildIn(x) => x.hash(hasher),
140 Reference(x) => x.type_hash(hasher, types),
141 Enumeration(x) => x.type_hash(hasher, types),
142 Dynamic(x) => x.type_hash(hasher, types),
143 All(x) => x.type_hash(hasher, types),
144 Choice(x) => x.type_hash(hasher, types),
145 Sequence(x) => x.type_hash(hasher, types),
146 ComplexType(x) => x.type_hash(hasher, types),
147 }
148 }
149
150 fn type_eq(&self, other: &Self, types: &Types) -> bool {
151 #[allow(clippy::enum_glob_use)]
152 use Type::*;
153
154 match (self, other) {
155 (Union(x), Union(y)) => x.type_eq(y, types),
156 (BuildIn(x), BuildIn(y)) => x == y,
157 (Reference(x), Reference(y)) => x.type_eq(y, types),
158 (Enumeration(x), Enumeration(y)) => x.type_eq(y, types),
159 (Dynamic(x), Dynamic(y)) => x.type_eq(y, types),
160 (All(x), All(y)) => x.type_eq(y, types),
161 (Choice(x), Choice(y)) => x.type_eq(y, types),
162 (Sequence(x), Sequence(y)) => x.type_eq(y, types),
163 (ComplexType(x), ComplexType(y)) => x.type_eq(y, types),
164 (_, _) => false,
165 }
166 }
167}
168
169impl BuildInInfo {
172 #[must_use]
174 pub fn as_str(&self) -> &'static str {
175 match self {
176 Self::U8 => "u8",
177 Self::U16 => "u16",
178 Self::U32 => "u32",
179 Self::U64 => "u64",
180 Self::U128 => "u128",
181 Self::Usize => "usize",
182
183 Self::I8 => "i8",
184 Self::I16 => "i16",
185 Self::I32 => "i32",
186 Self::I64 => "i64",
187 Self::I128 => "i128",
188 Self::Isize => "isize",
189
190 Self::F32 => "f32",
191 Self::F64 => "f64",
192
193 Self::Bool => "bool",
194 Self::String => "String",
195
196 Self::Custom(x) => x.name(),
197 }
198 }
199}
200
201impl Display for BuildInInfo {
202 fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult {
203 write!(f, "{}", self.as_str())
204 }
205}
206
207impl<T> TypeEq for Option<T>
210where
211 T: TypeEq,
212{
213 fn type_hash<H: Hasher>(&self, hasher: &mut H, types: &Types) {
214 if let Some(inner) = self {
215 hasher.write_u8(1);
216 inner.type_hash(hasher, types);
217 } else {
218 hasher.write_u8(0);
219 }
220 }
221
222 fn type_eq(&self, other: &Self, types: &Types) -> bool {
223 match (self, other) {
224 (Some(x), Some(y)) => x.type_eq(y, types),
225 (None, None) => true,
226 (_, _) => false,
227 }
228 }
229}