Skip to main content

zen_types/variable/
mod.rs

1use crate::symbol::Symbol;
2use crate::variable::map::Entry;
3use crate::variable::ref_ser::RefSerializer;
4use rust_decimal::Decimal;
5use rust_decimal::prelude::Zero;
6use serde_json::Value;
7use std::any::Any;
8use std::cell::RefCell;
9use std::fmt::{Debug, Display, Formatter};
10use std::ops::Deref;
11use std::rc::Rc;
12
13use crate::rcvalue::RcValue;
14pub use crate::variable::ref_deser::RefDeserializeError;
15use crate::variable::ref_deser::RefDeserializer;
16pub use de::VariableDeserializer;
17pub use impls::ToVariable;
18
19mod conv;
20mod de;
21mod impls;
22mod map;
23mod ref_deser;
24mod ref_ser;
25mod ser;
26
27pub use crate::rccell::RcCell;
28
29pub use crate::variable::map::{Iter as MapIter, VariableMap};
30
31thread_local! {
32    static DOLLAR_KEY_RC: Rc<str> = Rc::from("$");
33    static ROOT_KEY_RC: Rc<str> = Rc::from("$root");
34}
35
36pub enum Variable {
37    Null,
38    Bool(bool),
39    Number(Decimal),
40    String(Symbol),
41    Array(RcCell<Vec<Variable>>),
42    Object(RcCell<VariableMap>),
43    Dynamic(Rc<dyn DynamicVariable>),
44}
45
46pub trait DynamicVariable: Display {
47    fn type_name(&self) -> &'static str;
48
49    fn as_any(&self) -> &dyn Any;
50
51    fn to_value(&self) -> Value;
52}
53
54impl Variable {
55    pub fn dollar_key() -> Symbol {
56        Symbol::from_static("$")
57    }
58
59    pub fn root_key() -> Symbol {
60        Symbol::from_static("$root")
61    }
62
63    pub fn nodes_key() -> Symbol {
64        Symbol::from_static("$nodes")
65    }
66
67    pub fn key(name: &str) -> Symbol {
68        Symbol::from(name)
69    }
70
71    pub fn dollar_key_rc() -> Rc<str> {
72        DOLLAR_KEY_RC.with(Rc::clone)
73    }
74
75    pub fn root_key_rc() -> Rc<str> {
76        ROOT_KEY_RC.with(Rc::clone)
77    }
78
79    pub fn from_array(arr: Vec<Self>) -> Self {
80        Self::Array(Rc::new(RefCell::new(arr)))
81    }
82
83    pub fn serialize_ref(&self) -> RcValue {
84        RefSerializer::new().serialize(self)
85    }
86
87    pub fn deserialize_ref(serialized: RcValue) -> Result<Self, RefDeserializeError> {
88        RefDeserializer::new().deserialize(serialized)
89    }
90
91    pub fn from_object(obj: VariableMap) -> Self {
92        Self::Object(Rc::new(RefCell::new(obj)))
93    }
94
95    pub fn empty_object() -> Self {
96        Variable::Object(Default::default())
97    }
98
99    pub fn empty_array() -> Self {
100        Variable::Array(Default::default())
101    }
102
103    pub fn as_str(&self) -> Option<&str> {
104        match self {
105            Variable::String(s) => Some(s.as_ref()),
106            _ => None,
107        }
108    }
109
110    pub fn as_rc_str(&self) -> Option<Rc<str>> {
111        match self {
112            Variable::String(s) => Some(Rc::from(s.as_str())),
113            _ => None,
114        }
115    }
116
117    pub fn as_sym(&self) -> Option<&Symbol> {
118        match self {
119            Variable::String(s) => Some(s),
120            _ => None,
121        }
122    }
123
124    pub fn as_array(&self) -> Option<RcCell<Vec<Variable>>> {
125        match self {
126            Variable::Array(arr) => Some(arr.clone()),
127            _ => None,
128        }
129    }
130
131    pub fn is_array(&self) -> bool {
132        match self {
133            Variable::Array(_) => true,
134            _ => false,
135        }
136    }
137
138    pub fn as_object(&self) -> Option<RcCell<VariableMap>> {
139        match self {
140            Variable::Object(obj) => Some(obj.clone()),
141            _ => None,
142        }
143    }
144
145    pub fn is_object(&self) -> bool {
146        match self {
147            Variable::Object(_) => true,
148            _ => false,
149        }
150    }
151
152    pub fn as_bool(&self) -> Option<bool> {
153        match self {
154            Variable::Bool(b) => Some(*b),
155            _ => None,
156        }
157    }
158
159    pub fn as_number(&self) -> Option<Decimal> {
160        match self {
161            Variable::Number(n) => Some(*n),
162            _ => None,
163        }
164    }
165
166    pub fn type_name(&self) -> &'static str {
167        match self {
168            Variable::Null => "null",
169            Variable::Bool(_) => "bool",
170            Variable::Number(_) => "number",
171            Variable::String(_) => "string",
172            Variable::Array(_) => "array",
173            Variable::Object(_) => "object",
174            Variable::Dynamic(d) => d.type_name(),
175        }
176    }
177
178    pub fn dynamic<T: DynamicVariable + 'static>(&self) -> Option<&T> {
179        match self {
180            Variable::Dynamic(d) => d.as_any().downcast_ref::<T>(),
181            _ => None,
182        }
183    }
184
185    pub fn to_value(&self) -> Value {
186        Value::from(self.shallow_clone())
187    }
188
189    pub fn dot(&self, key: &str) -> Option<Variable> {
190        key.split('.')
191            .try_fold(self.shallow_clone(), |var, part| match var {
192                Variable::Object(obj) => {
193                    let reference = obj.borrow();
194                    reference.get_str(part).map(|v| v.shallow_clone())
195                }
196                _ => None,
197            })
198    }
199
200    fn dot_head_detach(&self, key: &str) -> (Variable, Option<Variable>) {
201        let mut parts = Vec::from_iter(key.split('.'));
202        parts.pop();
203
204        let cloned_self = self.depth_clone(1);
205        let head = parts
206            .iter()
207            .try_fold(cloned_self.shallow_clone(), |var, part| match var {
208                Variable::Object(obj) => {
209                    let mut obj_ref = obj.borrow_mut();
210                    Some(match obj_ref.entry(Symbol::from(*part)) {
211                        Entry::Occupied(mut occ) => {
212                            let var = occ.get();
213                            let new_obj = match var {
214                                Variable::Object(_) => var.depth_clone(1),
215                                _ => Variable::empty_object(),
216                            };
217
218                            occ.insert(new_obj.shallow_clone());
219                            new_obj
220                        }
221                        Entry::Vacant(vac) => vac.insert(Self::empty_object()).shallow_clone(),
222                    })
223                }
224                _ => None,
225            });
226
227        (cloned_self, head)
228    }
229
230    pub fn dot_remove(&self, key: &str) -> Option<Variable> {
231        let mut parts = key.split('.');
232        let last_part = parts.next_back()?;
233        let head = parts.try_fold(self.shallow_clone(), |var, part| match var {
234            Variable::Object(obj) => {
235                let mut obj_ref = obj.borrow_mut();
236                Some(match obj_ref.entry(Symbol::from(part)) {
237                    Entry::Occupied(occ) => occ.get().shallow_clone(),
238                    Entry::Vacant(vac) => vac.insert(Self::empty_object()).shallow_clone(),
239                })
240            }
241            _ => None,
242        })?;
243        let Variable::Object(object_ref) = head else {
244            return None;
245        };
246
247        let mut object = object_ref.borrow_mut();
248        object.remove_str(last_part)
249    }
250
251    pub fn dot_insert(&self, key: &str, variable: Variable) -> Option<Variable> {
252        let mut parts = key.split('.');
253        let last_part = parts.next_back()?;
254        let head = parts.try_fold(self.shallow_clone(), |var, part| match var {
255            Variable::Object(obj) => {
256                let mut obj_ref = obj.borrow_mut();
257                Some(match obj_ref.entry(Symbol::from(part)) {
258                    Entry::Occupied(occ) => occ.get().shallow_clone(),
259                    Entry::Vacant(vac) => vac.insert(Self::empty_object()).shallow_clone(),
260                })
261            }
262            _ => None,
263        })?;
264        let Variable::Object(object_ref) = head else {
265            return None;
266        };
267
268        let mut object = object_ref.borrow_mut();
269        object.insert(Symbol::from(last_part), variable)
270    }
271
272    pub fn dot_insert_detached(&self, key: &str, variable: Variable) -> Option<Variable> {
273        let last_part = key.split('.').last()?;
274        let (new_var, head_opt) = self.dot_head_detach(key);
275        let head = head_opt?;
276        let Variable::Object(object_ref) = head else {
277            return None;
278        };
279
280        let mut object = object_ref.borrow_mut();
281        object.insert(Symbol::from(last_part), variable);
282        Some(new_var)
283    }
284
285    pub fn merge(&mut self, patch: &Variable) -> Variable {
286        let _ = merge_variables(self, patch, true, MergeStrategy::InPlace);
287
288        self.shallow_clone()
289    }
290
291    pub fn merge_clone(&mut self, patch: &Variable) -> Variable {
292        let mut new_self = self.shallow_clone();
293
294        let _ = merge_variables(&mut new_self, patch, true, MergeStrategy::CloneOnWrite);
295        new_self
296    }
297
298    pub fn shallow_clone(&self) -> Self {
299        match self {
300            Variable::Null => Variable::Null,
301            Variable::Bool(b) => Variable::Bool(*b),
302            Variable::Number(n) => Variable::Number(*n),
303            Variable::String(s) => Variable::String(s.clone()),
304            Variable::Array(a) => Variable::Array(a.clone()),
305            Variable::Object(o) => Variable::Object(o.clone()),
306            Variable::Dynamic(d) => Variable::Dynamic(d.clone()),
307        }
308    }
309
310    pub fn deep_clone(&self) -> Self {
311        match self {
312            Variable::Array(a) => {
313                let arr = a.borrow();
314                Variable::from_array(arr.iter().map(|v| v.deep_clone()).collect())
315            }
316            Variable::Object(o) => {
317                let obj = o.borrow();
318                Variable::from_object(
319                    obj.iter()
320                        .map(|(k, v)| (k.clone(), v.deep_clone()))
321                        .collect(),
322                )
323            }
324            _ => self.shallow_clone(),
325        }
326    }
327
328    pub fn depth_clone(&self, depth: usize) -> Self {
329        match depth.is_zero() {
330            true => self.shallow_clone(),
331            false => match self {
332                Variable::Array(a) => {
333                    let arr = a.borrow();
334                    Variable::from_array(arr.iter().map(|v| v.depth_clone(depth - 1)).collect())
335                }
336                Variable::Object(o) => {
337                    let obj = o.borrow();
338                    Variable::from_object(
339                        obj.iter()
340                            .map(|(k, v)| (k.clone(), v.depth_clone(depth - 1)))
341                            .collect(),
342                    )
343                }
344                _ => self.shallow_clone(),
345            },
346        }
347    }
348}
349
350impl Clone for Variable {
351    fn clone(&self) -> Self {
352        self.shallow_clone()
353    }
354}
355
356#[derive(Copy, Clone)]
357enum MergeStrategy {
358    InPlace,
359    CloneOnWrite,
360}
361
362fn merge_variables(
363    doc: &mut Variable,
364    patch: &Variable,
365    top_level: bool,
366    strategy: MergeStrategy,
367) -> bool {
368    if patch.is_array() && top_level {
369        *doc = patch.shallow_clone();
370        return true;
371    }
372
373    if !patch.is_object() && top_level {
374        return false;
375    }
376
377    if doc.is_object() && patch.is_object() {
378        let doc_ref = doc.as_object().unwrap();
379        let patch_ref = patch.as_object().unwrap();
380        if RcCell::ptr_eq(&doc_ref, &patch_ref) {
381            return false;
382        }
383
384        let patch = patch_ref.borrow();
385        match strategy {
386            MergeStrategy::InPlace => {
387                let mut map = doc_ref.borrow_mut();
388                for (key, value) in patch.deref() {
389                    if value == &Variable::Null {
390                        map.remove(key);
391                    } else {
392                        let entry = map.entry(key.clone()).or_insert(Variable::Null);
393                        merge_variables(entry, value, false, strategy);
394                    }
395                }
396
397                return true;
398            }
399            MergeStrategy::CloneOnWrite => {
400                let mut changed = false;
401                let mut new_map: Option<VariableMap> = None;
402
403                for (key, value) in patch.deref() {
404                    // Get or create the new map if we haven't yet
405                    let map = if let Some(ref mut m) = new_map {
406                        m
407                    } else {
408                        let m = doc_ref.borrow().clone();
409                        new_map = Some(m);
410                        new_map.as_mut().unwrap()
411                    };
412
413                    if value == &Variable::Null {
414                        // Remove null values
415                        if map.remove(key).is_some() {
416                            changed = true;
417                        }
418                    } else {
419                        // Handle nested merging
420                        let entry = map.entry(key.clone()).or_insert(Variable::Null);
421                        if merge_variables(entry, value, false, strategy) {
422                            changed = true;
423                        }
424                    }
425                }
426
427                // Only update doc if changes were made
428                if changed {
429                    if let Some(new_map) = new_map {
430                        *doc = Variable::Object(Rc::new(RefCell::new(new_map)));
431                    }
432                    return true;
433                }
434
435                return false;
436            }
437        }
438    } else {
439        let new_value = patch.shallow_clone();
440        if *doc != new_value {
441            *doc = new_value;
442            return true;
443        }
444
445        return false;
446    }
447}
448
449impl Default for Variable {
450    fn default() -> Self {
451        Variable::Null
452    }
453}
454
455impl Display for Variable {
456    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
457        match self {
458            Variable::Null => write!(f, "null"),
459            Variable::Bool(b) => match *b {
460                true => write!(f, "true"),
461                false => write!(f, "false"),
462            },
463            Variable::Number(n) => write!(f, "{n}"),
464            Variable::String(s) => write!(f, "\"{s}\""),
465            Variable::Array(arr) => {
466                let arr = arr.borrow();
467                let s = arr
468                    .iter()
469                    .map(|v| v.to_string())
470                    .collect::<Vec<String>>()
471                    .join(",");
472                write!(f, "[{s}]")
473            }
474            Variable::Object(obj) => {
475                let obj = obj.borrow();
476                let s = obj
477                    .iter()
478                    .map(|(k, v)| format!("\"{k}\":{v}"))
479                    .collect::<Vec<String>>()
480                    .join(",");
481
482                write!(f, "{{{s}}}")
483            }
484            Variable::Dynamic(d) => write!(f, "{d}"),
485        }
486    }
487}
488
489impl Debug for Variable {
490    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
491        write!(f, "{}", self)
492    }
493}
494
495impl PartialEq for Variable {
496    fn eq(&self, other: &Self) -> bool {
497        match (&self, &other) {
498            (Variable::Null, Variable::Null) => true,
499            (Variable::Bool(b1), Variable::Bool(b2)) => b1 == b2,
500            (Variable::Number(n1), Variable::Number(n2)) => n1 == n2,
501            (Variable::String(s1), Variable::String(s2)) => s1.as_str() == s2.as_str(),
502            (Variable::Array(a1), Variable::Array(a2)) => a1 == a2,
503            (Variable::Object(obj1), Variable::Object(obj2)) => obj1 == obj2,
504            (Variable::Dynamic(d1), Variable::Dynamic(d2)) => Rc::ptr_eq(d1, d2),
505            _ => false,
506        }
507    }
508}
509
510impl Eq for Variable {}
511
512#[cfg(test)]
513mod tests {
514    use crate::variable::Variable;
515    use rust_decimal_macros::dec;
516    use serde_json::json;
517
518    #[test]
519    fn insert_detached() {
520        let some_data: Variable = json!({ "customer": { "firstName": "John" }}).into();
521
522        let a_a = some_data
523            .dot_insert_detached("a.a", Variable::Number(dec!(1)))
524            .unwrap();
525        let a_b = a_a
526            .dot_insert_detached("a.b", Variable::Number(dec!(2)))
527            .unwrap();
528        let a_c = a_b
529            .dot_insert_detached("a.c", Variable::Number(dec!(3)))
530            .unwrap();
531
532        assert_eq!(a_a.dot("a"), Some(Variable::from(json!({ "a": 1 }))));
533        assert_eq!(
534            a_b.dot("a"),
535            Some(Variable::from(json!({ "a": 1, "b": 2 })))
536        );
537        assert_eq!(
538            a_c.dot("a"),
539            Some(Variable::from(json!({ "a": 1, "b": 2, "c": 3 })))
540        );
541    }
542}