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