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