1use crate::variable_type::VariableType;
2use ahash::{HashMap, HashMapExt};
3use rust_decimal::prelude::Zero;
4use std::cell::RefCell;
5use std::collections::hash_map::Entry;
6use std::rc::Rc;
7
8impl VariableType {
9 pub fn iterator(&self) -> Option<Rc<VariableType>> {
10 match self {
11 VariableType::Array(item) => Some(item.clone()),
12 VariableType::Interval => Some(Rc::new(VariableType::Number)),
13 _ => None,
14 }
15 }
16
17 pub fn as_const_str(&self) -> Option<Rc<str>> {
18 match self {
19 VariableType::Const(s) => Some(s.clone()),
20 _ => None,
21 }
22 }
23
24 pub fn get(&self, key: &str) -> VariableType {
25 match self {
26 VariableType::Object(obj) => {
27 let obj = obj.borrow();
28 obj.get(key).cloned().unwrap_or(VariableType::Any)
29 }
30 _ => VariableType::Null,
31 }
32 }
33
34 pub fn satisfies(&self, constraint: &Self) -> bool {
35 match (self, constraint) {
36 (VariableType::Any, _) | (_, VariableType::Any) => true,
37 (VariableType::Null, VariableType::Null) => true,
38 (VariableType::Bool, VariableType::Bool) => true,
39 (VariableType::String, VariableType::String) => true,
40 (VariableType::Number, VariableType::Number) => true,
41 (VariableType::Date, VariableType::Date) => true,
42 (VariableType::Number, VariableType::Date) => true,
43 (_, VariableType::Date) if self.widen().is_string() => true,
44 (VariableType::Interval, VariableType::Interval) => true,
45 (VariableType::Array(a1), VariableType::Array(a2)) => a1.satisfies(a2),
46 (VariableType::Object(o1), VariableType::Object(o2)) => {
47 let o1 = o1.borrow();
48 let o2 = o2.borrow();
49
50 o1.iter()
51 .all(|(k, v)| o2.get(k).is_some_and(|tv| v.satisfies(tv)))
52 }
53
54 (VariableType::Const(c1), VariableType::Const(c2)) => c1 == c2,
55 (VariableType::Const(c), VariableType::Enum(_, e)) => e.iter().any(|e| e == c),
56 (VariableType::Const(_), VariableType::String) => true,
57 (VariableType::String, VariableType::Const(_)) => true,
58
59 (VariableType::Enum(_, e1), VariableType::Enum(_, e2)) => {
60 e1.iter().all(|c| e2.contains(c))
61 }
62 (VariableType::Enum(_, e), VariableType::Const(c)) => e.iter().all(|i| i == c),
63 (VariableType::Enum(_, _), VariableType::String) => true,
64 (VariableType::String, VariableType::Enum(_, _)) => true,
65
66 (_, _) => false,
67 }
68 }
69
70 pub fn is_array(&self) -> bool {
71 match self {
72 VariableType::Any | VariableType::Array(_) => true,
73 _ => false,
74 }
75 }
76
77 pub fn is_iterable(&self) -> bool {
78 match self {
79 VariableType::Any | VariableType::Interval | VariableType::Array(_) => true,
80 _ => false,
81 }
82 }
83
84 pub fn is_string(&self) -> bool {
85 match self {
86 VariableType::String => true,
87 _ => false,
88 }
89 }
90
91 pub fn is_object(&self) -> bool {
92 match self {
93 VariableType::Any | VariableType::Object(_) => true,
94 _ => false,
95 }
96 }
97
98 pub fn is_null(&self) -> bool {
99 match self {
100 VariableType::Null => true,
101 _ => false,
102 }
103 }
104
105 pub fn widen(&self) -> Self {
106 match self {
107 VariableType::Const(_) | VariableType::Enum(_, _) => VariableType::String,
108 _ => self.clone(),
109 }
110 }
111
112 pub fn merge(&self, other: &Self) -> Self {
113 match (self, other) {
114 (VariableType::Any, _) | (_, VariableType::Any) => VariableType::Any,
115 (VariableType::Null, VariableType::Null) => VariableType::Null,
116 (VariableType::Bool, VariableType::Bool) => VariableType::Bool,
117 (VariableType::String, VariableType::String) => VariableType::String,
118 (VariableType::Number, VariableType::Number) => VariableType::Number,
119 (VariableType::Date, VariableType::Date) => VariableType::Date,
120 (VariableType::Interval, VariableType::Interval) => VariableType::Interval,
121 (VariableType::Array(a1), VariableType::Array(a2)) => {
122 if Rc::ptr_eq(a1, a2) {
123 VariableType::Array(a1.clone())
124 } else {
125 VariableType::Array(Rc::new(a1.as_ref().merge(a2.as_ref())))
126 }
127 }
128
129 (VariableType::Object(o1), VariableType::Object(o2)) => {
130 let o1 = o1.borrow();
131 let o2 = o2.borrow();
132
133 let mut merged = HashMap::with_capacity(o1.len().max(o2.len()));
134 for (k, v) in o1.iter() {
135 merged.insert(k.clone(), v.clone());
136 }
137
138 for (k, v) in o2.iter() {
139 match merged.entry(k.clone()) {
140 Entry::Occupied(mut entry) => {
141 let current = entry.get();
142 let merged_value = current.merge(v);
143 entry.insert(merged_value);
144 }
145 Entry::Vacant(entry) => {
146 entry.insert(v.clone());
147 }
148 }
149 }
150
151 VariableType::Object(Rc::new(RefCell::new(merged)))
152 }
153
154 (VariableType::Const(c), VariableType::Enum(_, values)) => {
155 let mut merged = values.clone();
156 if !merged.contains(c) {
157 merged.push(c.clone());
158 }
159
160 VariableType::Enum(None, merged)
161 }
162 (VariableType::Const(c1), VariableType::Const(c2)) => {
163 if Rc::ptr_eq(c1, c2) || c1 == c2 {
164 VariableType::Const(c1.clone())
165 } else {
166 VariableType::Enum(None, vec![c1.clone(), c2.clone()])
167 }
168 }
169 (VariableType::Const(_), VariableType::String)
170 | (VariableType::String, VariableType::Const(_)) => VariableType::String,
171
172 (VariableType::Enum(n1, a), VariableType::Enum(n2, b)) => {
173 let mut merged = a.clone();
174 for val in b {
175 if !merged.contains(val) {
176 merged.push(val.clone());
177 }
178 }
179
180 let name = match (n1, n2) {
181 (Some(n1), Some(n2)) => Some(Rc::<str>::from(format!("{} | {}", n1, n2))),
182 _ => None,
183 };
184
185 VariableType::Enum(name, merged)
186 }
187
188 (VariableType::Enum(_, values), VariableType::Const(c)) => {
189 let mut merged = values.clone();
190 if !merged.contains(c) {
191 merged.push(c.clone());
192 }
193 VariableType::Enum(None, merged)
194 }
195
196 (VariableType::Enum(_, _), VariableType::String)
197 | (VariableType::String, VariableType::Enum(_, _)) => VariableType::String,
198
199 (_, _) => VariableType::Any,
200 }
201 }
202
203 pub fn shallow_clone(&self) -> Self {
204 match self {
205 VariableType::Any => VariableType::Any,
206 VariableType::Null => VariableType::Null,
207 VariableType::Bool => VariableType::Bool,
208 VariableType::String => VariableType::String,
209 VariableType::Number => VariableType::Number,
210 VariableType::Date => VariableType::Date,
211 VariableType::Interval => VariableType::Interval,
212 VariableType::Array(arr) => VariableType::Array(arr.clone()),
213 VariableType::Object(obj) => VariableType::Object(obj.clone()),
214 VariableType::Const(c) => VariableType::Const(c.clone()),
215 VariableType::Enum(name, options) => VariableType::Enum(name.clone(), options.clone()),
216 }
217 }
218
219 pub fn dot_head(&self, key: &str) -> Option<Self> {
220 let mut parts = Vec::from_iter(key.split('.'));
221 parts.pop();
222
223 parts
224 .iter()
225 .try_fold(self.shallow_clone(), |var, part| match var {
226 VariableType::Object(obj) => {
227 let mut obj_ref = obj.borrow_mut();
228 Some(match obj_ref.entry(Rc::from(*part)) {
229 Entry::Occupied(occ) => occ.get().shallow_clone(),
230 Entry::Vacant(vac) => vac.insert(Self::empty_object()).shallow_clone(),
231 })
232 }
233 _ => None,
234 })
235 }
236
237 pub fn dot_head_detach(&self, key: &str) -> (Self, Option<Self>) {
238 let mut parts = Vec::from_iter(key.split('.'));
239 parts.pop();
240
241 let cloned_self = self.depth_clone(1);
242 let head = parts
243 .iter()
244 .try_fold(cloned_self.shallow_clone(), |var, part| match var {
245 VariableType::Object(obj) => {
246 let mut obj_ref = obj.borrow_mut();
247 Some(match obj_ref.entry(Rc::from(*part)) {
248 Entry::Occupied(mut occ) => {
249 let var = occ.get();
250 let new_obj = match var {
251 VariableType::Object(_) => var.depth_clone(1),
252 _ => VariableType::empty_object(),
253 };
254
255 occ.insert(new_obj.shallow_clone());
256 new_obj
257 }
258 Entry::Vacant(vac) => vac.insert(Self::empty_object()).shallow_clone(),
259 })
260 }
261 _ => None,
262 });
263
264 (cloned_self, head)
265 }
266
267 pub fn depth_clone(&self, depth: usize) -> Self {
268 match depth.is_zero() {
269 true => self.shallow_clone(),
270 false => match self {
271 VariableType::Object(o) => {
272 let obj = o.borrow();
273 VariableType::Object(Rc::new(RefCell::new(
274 obj.iter()
275 .map(|(k, v)| (k.clone(), v.depth_clone(depth - 1)))
276 .collect(),
277 )))
278 }
279 _ => self.shallow_clone(),
280 },
281 }
282 }
283
284 pub fn empty_object() -> Self {
285 VariableType::Object(Rc::new(RefCell::new(HashMap::new())))
286 }
287
288 pub fn dot_insert_detached(&self, key: &str, variable: Self) -> Option<Self> {
289 let last_part = key.split('.').last()?;
290 let (new_var, head_opt) = self.dot_head_detach(key);
291 let head = head_opt?;
292 let VariableType::Object(object_ref) = head else {
293 return None;
294 };
295
296 let mut object = object_ref.borrow_mut();
297 object.insert(Rc::from(last_part), variable);
298 Some(new_var)
299 }
300
301 pub fn dot_insert(&self, key: &str, variable: Self) -> Option<Self> {
302 let last_part = key.split('.').last()?;
303 let head = self.dot_head(key)?;
304 let Self::Object(object_ref) = head else {
305 return None;
306 };
307
308 let mut object = object_ref.borrow_mut();
309 object.insert(Rc::from(last_part), variable)
310 }
311
312 pub fn dot(&self, key: &str) -> Option<Self> {
313 key.split('.')
314 .try_fold(self.shallow_clone(), |var, part| match var {
315 Self::Object(obj) => {
316 let reference = obj.borrow();
317 reference.get(part).map(|v| v.shallow_clone())
318 }
319 _ => None,
320 })
321 }
322}