Skip to main content

zen_types/variable_type/
mod.rs

1mod conv;
2mod util;
3
4use ahash::HashMap;
5pub use ahash::HashMapExt as VariableMapExt;
6use serde::ser::{SerializeMap, SerializeTupleVariant};
7use serde::{Deserialize, Serialize, Serializer};
8use std::cell::RefCell;
9use std::fmt::{Display, Write};
10use std::hash::{Hash, Hasher};
11use std::rc::Rc;
12
13type RcCell<T> = Rc<RefCell<T>>;
14
15pub const MAX_TYPE_DEPTH: usize = 32;
16
17#[derive(Clone, Eq, PartialEq, Deserialize)]
18pub enum VariableType {
19    Any,
20    Null,
21    Bool,
22    String,
23    Number,
24    Date,
25    Interval,
26    Array(Rc<VariableType>),
27    Object(RcCell<HashMap<Rc<str>, VariableType>>),
28
29    Const(Rc<str>),
30    Enum(Option<Rc<str>>, Vec<Rc<str>>),
31    Nullable(Rc<VariableType>),
32}
33
34impl VariableType {
35    pub fn array(self) -> Self {
36        Self::Array(Rc::new(self))
37    }
38}
39
40const TYPE_NAME: &str = "VariableType";
41
42struct Guarded<'a> {
43    inner: &'a VariableType,
44    path: &'a [*const ()],
45}
46
47struct GuardedFields<'a> {
48    fields: &'a HashMap<Rc<str>, VariableType>,
49    path: Vec<*const ()>,
50}
51
52impl Serialize for VariableType {
53    fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
54        Guarded {
55            inner: self,
56            path: &[],
57        }
58        .serialize(serializer)
59    }
60}
61
62impl Serialize for Guarded<'_> {
63    fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
64        match self.inner {
65            VariableType::Any => serializer.serialize_unit_variant(TYPE_NAME, 0, "Any"),
66            VariableType::Null => serializer.serialize_unit_variant(TYPE_NAME, 1, "Null"),
67            VariableType::Bool => serializer.serialize_unit_variant(TYPE_NAME, 2, "Bool"),
68            VariableType::String => serializer.serialize_unit_variant(TYPE_NAME, 3, "String"),
69            VariableType::Number => serializer.serialize_unit_variant(TYPE_NAME, 4, "Number"),
70            VariableType::Date => serializer.serialize_unit_variant(TYPE_NAME, 5, "Date"),
71            VariableType::Interval => serializer.serialize_unit_variant(TYPE_NAME, 6, "Interval"),
72            VariableType::Array(inner) => serializer.serialize_newtype_variant(
73                TYPE_NAME,
74                7,
75                "Array",
76                &Guarded {
77                    inner,
78                    path: self.path,
79                },
80            ),
81            VariableType::Object(obj) => {
82                let ptr = Rc::as_ptr(obj) as *const ();
83                let cut = self.path.len() >= MAX_TYPE_DEPTH || self.path.contains(&ptr);
84                let empty = HashMap::default();
85                let borrowed;
86                let fields: &HashMap<Rc<str>, VariableType> = if cut {
87                    &empty
88                } else {
89                    borrowed = obj.borrow();
90                    &borrowed
91                };
92                let mut path = self.path.to_vec();
93                path.push(ptr);
94                serializer.serialize_newtype_variant(
95                    TYPE_NAME,
96                    8,
97                    "Object",
98                    &GuardedFields { fields, path },
99                )
100            }
101            VariableType::Const(c) => {
102                serializer.serialize_newtype_variant(TYPE_NAME, 9, "Const", c.as_ref())
103            }
104            VariableType::Enum(name, values) => {
105                let mut tv = serializer.serialize_tuple_variant(TYPE_NAME, 10, "Enum", 2)?;
106                tv.serialize_field(name)?;
107                tv.serialize_field(values)?;
108                tv.end()
109            }
110            VariableType::Nullable(inner) => serializer.serialize_newtype_variant(
111                TYPE_NAME,
112                11,
113                "Nullable",
114                &Guarded {
115                    inner,
116                    path: self.path,
117                },
118            ),
119        }
120    }
121}
122
123impl Serialize for GuardedFields<'_> {
124    fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
125        let mut map = serializer.serialize_map(Some(self.fields.len()))?;
126        for (key, value) in self.fields.iter() {
127            map.serialize_entry(
128                key.as_ref(),
129                &Guarded {
130                    inner: value,
131                    path: &self.path,
132                },
133            )?;
134        }
135        map.end()
136    }
137}
138
139impl Default for VariableType {
140    fn default() -> Self {
141        VariableType::Null
142    }
143}
144
145impl std::fmt::Debug for VariableType {
146    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
147        std::fmt::Debug::fmt(
148            &Guarded {
149                inner: self,
150                path: &[],
151            },
152            f,
153        )
154    }
155}
156
157impl std::fmt::Debug for Guarded<'_> {
158    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
159        match self.inner {
160            VariableType::Any => f.write_str("Any"),
161            VariableType::Null => f.write_str("Null"),
162            VariableType::Bool => f.write_str("Bool"),
163            VariableType::String => f.write_str("String"),
164            VariableType::Number => f.write_str("Number"),
165            VariableType::Date => f.write_str("Date"),
166            VariableType::Interval => f.write_str("Interval"),
167            VariableType::Array(inner) | VariableType::Nullable(inner) => {
168                let name = if matches!(self.inner, VariableType::Array(_)) {
169                    "Array"
170                } else {
171                    "Nullable"
172                };
173                f.debug_tuple(name)
174                    .field(&Guarded {
175                        inner,
176                        path: self.path,
177                    })
178                    .finish()
179            }
180            VariableType::Const(value) => f.debug_tuple("Const").field(value).finish(),
181            VariableType::Enum(name, values) => {
182                f.debug_tuple("Enum").field(name).field(values).finish()
183            }
184            VariableType::Object(obj) => {
185                let ptr = Rc::as_ptr(obj) as *const ();
186                if self.path.len() >= MAX_TYPE_DEPTH || self.path.contains(&ptr) {
187                    return f.write_str("Object(<recursive>)");
188                }
189                let mut path = self.path.to_vec();
190                path.push(ptr);
191                f.debug_tuple("Object")
192                    .field(&DebugCell(GuardedFields {
193                        fields: &obj.borrow(),
194                        path,
195                    }))
196                    .finish()
197            }
198        }
199    }
200}
201
202struct DebugCell<'a>(GuardedFields<'a>);
203
204impl std::fmt::Debug for DebugCell<'_> {
205    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
206        f.debug_struct("RefCell").field("value", &self.0).finish()
207    }
208}
209
210impl std::fmt::Debug for GuardedFields<'_> {
211    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
212        f.debug_map()
213            .entries(self.fields.iter().map(|(key, value)| {
214                (
215                    key,
216                    Guarded {
217                        inner: value,
218                        path: &self.path,
219                    },
220                )
221            }))
222            .finish()
223    }
224}
225
226impl Display for VariableType {
227    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
228        match self {
229            VariableType::Any => write!(f, "any"),
230            VariableType::Null => write!(f, "null"),
231            VariableType::Bool => write!(f, "bool"),
232            VariableType::String => write!(f, "string"),
233            VariableType::Number => write!(f, "number"),
234            VariableType::Date => write!(f, "date"),
235            VariableType::Interval => write!(f, "interval"),
236            VariableType::Const(c) => write!(f, "\"{c}\""),
237            VariableType::Enum(name, e) => {
238                if let Some(name) = name {
239                    return name.fmt(f);
240                }
241
242                let mut first = true;
243                for s in e.iter() {
244                    if !first {
245                        f.write_str(" | ")?;
246                    }
247
248                    f.write_char('"')?;
249                    f.write_str(s)?;
250                    f.write_char('"')?;
251                    first = false;
252                }
253
254                Ok(())
255            }
256            VariableType::Array(v) => write!(f, "{v}[]"),
257            VariableType::Object(_) => write!(f, "object"),
258            VariableType::Nullable(inner) => write!(f, "{inner}?"),
259        }
260    }
261}
262
263impl Hash for VariableType {
264    fn hash<H: Hasher>(&self, state: &mut H) {
265        match &self {
266            VariableType::Any => 0.hash(state),
267            VariableType::Null => 1.hash(state),
268            VariableType::Bool => 2.hash(state),
269            VariableType::String => 3.hash(state),
270            VariableType::Number => 4.hash(state),
271            VariableType::Date => 5.hash(state),
272            VariableType::Interval => 6.hash(state),
273            VariableType::Const(c) => {
274                7.hash(state);
275                c.hash(state)
276            }
277            VariableType::Enum(name, e) => {
278                8.hash(state);
279                name.hash(state);
280                e.hash(state)
281            }
282            VariableType::Array(arr) => {
283                9.hash(state);
284                arr.hash(state)
285            }
286            VariableType::Object(obj) => {
287                10.hash(state);
288
289                let obj = obj.borrow();
290                let mut pairs: Vec<_> = obj.iter().collect();
291                pairs.sort_by_key(|i| i.0);
292
293                Hash::hash(&pairs, state);
294            }
295            VariableType::Nullable(inner) => {
296                11.hash(state);
297                inner.hash(state);
298            }
299        }
300    }
301}