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