jsonata_rs/evaluator/
value.rs

1use std::borrow::Cow;
2
3use bitflags::bitflags;
4use bumpalo::boxed::Box;
5use bumpalo::collections::String as BumpString;
6use bumpalo::collections::Vec as BumpVec;
7use bumpalo::Bump;
8use hashbrown::DefaultHashBuilder;
9use hashbrown::HashMap;
10
11use super::frame::Frame;
12use super::functions::FunctionContext;
13use crate::parser::ast::{Ast, AstKind, RegexLiteral};
14use crate::{Error, Result};
15
16pub mod impls;
17pub mod iterator;
18mod range;
19pub mod serialize;
20
21use self::range::Range;
22use self::serialize::{DumpFormatter, PrettyFormatter, Serializer};
23pub use iterator::MemberIterator;
24
25bitflags! {
26    #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
27    pub struct ArrayFlags: u8 {
28        const SEQUENCE     = 0b00000001;
29        const SINGLETON    = 0b00000010;
30        const CONS         = 0b00000100;
31        const WRAPPED      = 0b00001000;
32        const TUPLE_STREAM = 0b00010000;
33    }
34}
35
36pub const UNDEFINED: Value = Value::Undefined;
37pub const TRUE: Value = Value::Bool(true);
38pub const FALSE: Value = Value::Bool(false);
39
40/// The core value type for input, output and evaluation.
41///
42/// There's a lot of lifetimes here to avoid
43/// cloning any part of the input that should be kept in the output, avoiding heap allocations for
44/// every Value, and allowing structural sharing.
45///
46/// Values are all allocated in a Bump arena, making them contiguous in memory and further avoiding
47/// heap allocations for every one.
48pub enum Value<'a> {
49    Undefined,
50    Null,
51    Number(f64),
52    Bool(bool),
53    String(BumpString<'a>),
54    Regex(std::boxed::Box<RegexLiteral>),
55    Array(BumpVec<'a, &'a Value<'a>>, ArrayFlags),
56    Object(HashMap<BumpString<'a>, &'a Value<'a>, DefaultHashBuilder, &'a Bump>),
57    Range(Range<'a>),
58    Lambda {
59        ast: Box<'a, Ast>,
60        input: &'a Value<'a>,
61        frame: Frame<'a>,
62    },
63    NativeFn {
64        name: String,
65        arity: usize,
66        func: fn(FunctionContext<'a, '_>, &[&'a Value<'a>]) -> Result<&'a Value<'a>>,
67    },
68    Transformer {
69        pattern: std::boxed::Box<Ast>,
70        update: std::boxed::Box<Ast>,
71        delete: Option<std::boxed::Box<Ast>>,
72    },
73}
74
75#[allow(clippy::mut_from_ref)]
76impl<'a> Value<'a> {
77    pub fn undefined() -> &'a Value<'a> {
78        // SAFETY: The UNDEFINED const is Value<'static>, it doesn't reference any other Values,
79        // and there's no Drop implementation, so there shouldn't be an issue casting it to Value<'a>.
80        unsafe { std::mem::transmute::<&Value<'static>, &'a Value<'a>>(&UNDEFINED) }
81    }
82
83    pub fn null(arena: &Bump) -> &mut Value {
84        arena.alloc(Value::Null)
85    }
86
87    pub fn bool(value: bool) -> &'a Value<'a> {
88        if value {
89            unsafe { std::mem::transmute::<&Value<'static>, &'a Value<'a>>(&TRUE) }
90        } else {
91            unsafe { std::mem::transmute::<&Value<'static>, &'a Value<'a>>(&FALSE) }
92        }
93    }
94
95    pub fn number(arena: &Bump, value: impl Into<f64>) -> &mut Value {
96        arena.alloc(Value::Number(value.into()))
97    }
98
99    pub fn number_from_u128(arena: &Bump, value: u128) -> Result<&mut Value> {
100        let value_f64 = value as f64;
101        if value_f64 as u128 != value {
102            // number is too large to retain precision
103            return Err(Error::D1001NumberOfOutRange(value_f64));
104        };
105        Ok(arena.alloc(Value::Number(value_f64)))
106    }
107
108    pub fn string(arena: &'a Bump, value: &str) -> &'a mut Value<'a> {
109        arena.alloc(Value::String(BumpString::from_str_in(value, arena)))
110    }
111
112    pub fn array(arena: &Bump, flags: ArrayFlags) -> &mut Value {
113        let v = BumpVec::new_in(arena);
114        arena.alloc(Value::Array(v, flags))
115    }
116
117    pub fn array_from(
118        arena: &'a Bump,
119        arr: BumpVec<'a, &'a Value<'a>>,
120        flags: ArrayFlags,
121    ) -> &'a mut Value<'a> {
122        arena.alloc(Value::Array(arr, flags))
123    }
124
125    pub fn array_with_capacity(arena: &Bump, capacity: usize, flags: ArrayFlags) -> &mut Value {
126        arena.alloc(Value::Array(
127            BumpVec::with_capacity_in(capacity, arena),
128            flags,
129        ))
130    }
131
132    pub fn object(arena: &Bump) -> &mut Value {
133        arena.alloc(Value::Object(HashMap::new_in(arena)))
134    }
135
136    pub fn object_from<H>(
137        hash: &HashMap<BumpString<'a>, &'a Value<'a>, H, &'a Bump>,
138        arena: &'a Bump,
139    ) -> &'a mut Value<'a> {
140        let result = Value::object_with_capacity(arena, hash.len());
141        if let Value::Object(o) = result {
142            o.extend(hash.iter().map(|(k, v)| (k.clone(), *v)));
143        }
144        result
145    }
146
147    pub fn object_with_capacity(arena: &Bump, capacity: usize) -> &mut Value {
148        arena.alloc(Value::Object(HashMap::with_capacity_in(capacity, arena)))
149    }
150
151    pub fn lambda(
152        arena: &'a Bump,
153        node: &Ast,
154        input: &'a Value<'a>,
155        frame: Frame<'a>,
156    ) -> &'a mut Value<'a> {
157        arena.alloc(Value::Lambda {
158            ast: Box::new_in(node.clone(), arena),
159            input,
160            frame,
161        })
162    }
163
164    pub fn nativefn(
165        arena: &'a Bump,
166        name: &str,
167        arity: usize,
168        func: fn(FunctionContext<'a, '_>, &[&'a Value<'a>]) -> Result<&'a Value<'a>>,
169    ) -> &'a mut Value<'a> {
170        arena.alloc(Value::NativeFn {
171            name: name.to_string(),
172            arity,
173            func,
174        })
175    }
176
177    pub fn transformer(
178        arena: &'a Bump,
179        pattern: &std::boxed::Box<Ast>,
180        update: &std::boxed::Box<Ast>,
181        delete: &Option<std::boxed::Box<Ast>>,
182    ) -> &'a mut Value<'a> {
183        arena.alloc(Value::Transformer {
184            pattern: pattern.clone(),
185            update: update.clone(),
186            delete: delete.clone(),
187        })
188    }
189
190    pub fn range(arena: &'a Bump, start: isize, end: isize) -> &'a mut Value<'a> {
191        arena.alloc(Value::Range(Range::new(arena, start, end)))
192    }
193
194    pub fn range_from(arena: &'a Bump, range: &'a Range) -> &'a mut Value<'a> {
195        arena.alloc(Value::Range(range.clone()))
196    }
197
198    pub fn is_undefined(&self) -> bool {
199        matches!(*self, Value::Undefined)
200    }
201
202    pub fn is_null(&self) -> bool {
203        matches!(*self, Value::Null)
204    }
205
206    pub fn is_bool(&self) -> bool {
207        matches!(&self, Value::Bool(..))
208    }
209
210    pub fn is_number(&self) -> bool {
211        matches!(&self, Value::Number(..))
212    }
213
214    pub fn is_integer(&self) -> bool {
215        match self {
216            Value::Number(n) => match n.classify() {
217                std::num::FpCategory::Nan
218                | std::num::FpCategory::Infinite
219                | std::num::FpCategory::Subnormal => false,
220                _ => {
221                    let mantissa = n.trunc();
222                    n - mantissa == 0.0
223                }
224            },
225            _ => false,
226        }
227    }
228
229    pub fn is_array_of_valid_numbers(&self) -> Result<bool> {
230        match self {
231            Value::Array(ref a, _) => {
232                for member in a.iter() {
233                    if !member.is_valid_number()? {
234                        return Ok(false);
235                    }
236                }
237                Ok(true)
238            }
239            _ => Ok(false),
240        }
241    }
242
243    pub fn is_array_of_strings(&self) -> bool {
244        match self {
245            Value::Array(ref a, _) => {
246                for member in a.iter() {
247                    if !member.is_string() {
248                        return false;
249                    }
250                }
251                true
252            }
253            _ => false,
254        }
255    }
256
257    pub fn is_valid_number(&self) -> Result<bool> {
258        match self {
259            Value::Number(n) => {
260                if n.is_nan() {
261                    Ok(false)
262                } else if n.is_infinite() {
263                    Err(Error::D1001NumberOfOutRange(*n))
264                } else {
265                    Ok(true)
266                }
267            }
268            _ => Ok(false),
269        }
270    }
271
272    pub fn is_nan(&self) -> bool {
273        matches!(*self, Value::Number(n) if n.is_nan())
274    }
275
276    pub fn is_finite(&self) -> bool {
277        match self {
278            Value::Number(n) => n.is_finite(),
279            _ => false,
280        }
281    }
282
283    pub fn is_string(&self) -> bool {
284        matches!(*self, Value::String(..))
285    }
286
287    pub fn is_array(&self) -> bool {
288        matches!(*self, Value::Array(..) | Value::Range(..))
289    }
290
291    pub fn is_object(&self) -> bool {
292        matches!(*self, Value::Object(..))
293    }
294
295    pub fn is_function(&self) -> bool {
296        matches!(
297            *self,
298            Value::Lambda { .. } | Value::NativeFn { .. } | Value::Transformer { .. }
299        )
300    }
301
302    pub fn is_truthy(&'a self) -> bool {
303        match *self {
304            Value::Undefined => false,
305            Value::Null => false,
306            Value::Number(n) => n != 0.0,
307            Value::Bool(ref b) => *b,
308            Value::String(ref s) => !s.is_empty(),
309            Value::Array(ref a, _) => match a.len() {
310                0 => false,
311                1 => self.get_member(0).is_truthy(),
312                _ => {
313                    for item in self.members() {
314                        if item.is_truthy() {
315                            return true;
316                        }
317                    }
318                    false
319                }
320            },
321            Value::Object(ref o) => !o.is_empty(),
322            Value::Regex(_) => true, // Treat Regex as truthy if it exists
323            Value::Lambda { .. } | Value::NativeFn { .. } | Value::Transformer { .. } => false,
324            Value::Range(ref r) => !r.is_empty(),
325        }
326    }
327
328    pub fn get_member(&self, index: usize) -> &'a Value<'a> {
329        match *self {
330            Value::Array(ref array, _) => {
331                array.get(index).copied().unwrap_or_else(Value::undefined)
332            }
333            Value::Range(ref range) => range.nth(index).unwrap_or_else(Value::undefined),
334            _ => panic!("Not an array"),
335        }
336    }
337
338    pub fn members(&'a self) -> MemberIterator<'a> {
339        match self {
340            Value::Array(..) | Value::Range(..) => MemberIterator::new(self),
341            _ => panic!("Not an array"),
342        }
343    }
344
345    pub fn entries(&self) -> hashbrown::hash_map::Iter<'_, BumpString<'a>, &'a Value> {
346        match self {
347            Value::Object(map) => map.iter(),
348            _ => panic!("Not an object"),
349        }
350    }
351
352    pub fn arity(&self) -> usize {
353        match *self {
354            Value::Lambda { ref ast, .. } => {
355                if let AstKind::Lambda { ref args, .. } = ast.kind {
356                    args.len()
357                } else {
358                    panic!("Not a lambda function")
359                }
360            }
361            Value::NativeFn { arity, .. } => arity,
362            Value::Transformer { .. } => 1,
363            _ => panic!("Not a function"),
364        }
365    }
366
367    pub fn as_bool(&self) -> bool {
368        match *self {
369            Value::Bool(ref b) => *b,
370            _ => panic!("Not a bool"),
371        }
372    }
373
374    pub fn as_f64(&self) -> f64 {
375        match *self {
376            Value::Number(n) => n,
377            _ => panic!("Not a number"),
378        }
379    }
380
381    // TODO(math): Completely unchecked, audit usage
382    pub fn as_usize(&self) -> usize {
383        match *self {
384            Value::Number(n) => n as usize,
385            _ => panic!("Not a number"),
386        }
387    }
388
389    // TODO(math): Completely unchecked, audit usage
390    pub fn as_isize(&self) -> isize {
391        match *self {
392            Value::Number(n) => n as isize,
393            _ => panic!("Not a number"),
394        }
395    }
396
397    pub fn as_str(&self) -> Cow<'_, str> {
398        match *self {
399            Value::String(ref s) => Cow::from(s.as_str()),
400            _ => panic!("Not a string"),
401        }
402    }
403
404    pub fn len(&self) -> usize {
405        match *self {
406            Value::Array(ref array, _) => array.len(),
407            Value::Range(ref range) => range.len(),
408            _ => panic!("Not an array"),
409        }
410    }
411
412    pub fn is_empty(&self) -> bool {
413        match *self {
414            Value::Array(ref array, _) => array.is_empty(),
415            Value::Range(ref range) => range.is_empty(),
416            _ => panic!("Not an array"),
417        }
418    }
419
420    pub fn get_entry(&self, key: &str) -> &'a Value<'a> {
421        match *self {
422            Value::Object(ref map) => match map.get(key) {
423                Some(value) => value,
424                None => Value::undefined(),
425            },
426            _ => panic!("Not an object"),
427        }
428    }
429
430    pub fn remove_entry(&mut self, key: &str) {
431        match *self {
432            Value::Object(ref mut map) => map.remove(key),
433            _ => panic!("Not an object"),
434        };
435    }
436
437    pub fn push(&mut self, value: &'a Value<'a>) {
438        match *self {
439            Value::Array(ref mut array, _) => array.push(value),
440            _ => panic!("Not an array"),
441        }
442    }
443
444    pub fn insert(&mut self, key: &str, value: &'a Value<'a>) {
445        match *self {
446            Value::Object(ref mut map) => {
447                map.insert(BumpString::from_str_in(key, map.allocator()), value);
448            }
449            _ => panic!("Not an object"),
450        }
451    }
452
453    pub fn remove(&mut self, key: &str) {
454        match *self {
455            Value::Object(ref mut map) => map.remove(key),
456            _ => panic!("Not an object"),
457        };
458    }
459
460    pub fn flatten(&'a self, arena: &'a Bump) -> &'a mut Value<'a> {
461        let flattened = Self::array(arena, ArrayFlags::empty());
462        self._flatten(flattened)
463    }
464
465    fn _flatten(&'a self, flattened: &'a mut Value<'a>) -> &'a mut Value<'a> {
466        let mut flattened = flattened;
467
468        if self.is_array() {
469            for member in self.members() {
470                flattened = member._flatten(flattened);
471            }
472        } else {
473            flattened.push(self)
474        }
475
476        flattened
477    }
478
479    pub fn wrap_in_array(
480        arena: &'a Bump,
481        value: &'a Value<'a>,
482        flags: ArrayFlags,
483    ) -> &'a mut Value<'a> {
484        arena.alloc(Value::Array(bumpalo::vec![in arena; value], flags))
485    }
486
487    pub fn wrap_in_array_if_needed(
488        arena: &'a Bump,
489        value: &'a Value<'a>,
490        flags: ArrayFlags,
491    ) -> &'a Value<'a> {
492        if value.is_array() {
493            value
494        } else {
495            Value::wrap_in_array(arena, value, flags)
496        }
497    }
498
499    pub fn get_flags(&self) -> ArrayFlags {
500        match self {
501            Value::Array(_, flags) => *flags,
502            _ => panic!("Not an array"),
503        }
504    }
505
506    pub fn has_flags(&self, check_flags: ArrayFlags) -> bool {
507        match self {
508            Value::Array(_, flags) => flags.contains(check_flags),
509            _ => false,
510        }
511    }
512
513    pub fn clone(&'a self, arena: &'a Bump) -> &'a mut Value<'a> {
514        match self {
515            Self::Undefined => arena.alloc(Value::Undefined),
516            Self::Null => Value::null(arena),
517            Self::Number(n) => Value::number(arena, *n),
518            Self::Bool(b) => arena.alloc(Value::Bool(*b)),
519            Self::String(s) => arena.alloc(Value::String(s.clone())),
520            Self::Array(a, f) => Value::array_from(arena, a.clone(), *f),
521            Self::Object(o) => Value::object_from(o, arena),
522            Self::Lambda { ast, input, frame } => Value::lambda(arena, ast, input, frame.clone()),
523            Self::NativeFn { name, arity, func } => Value::nativefn(arena, name, *arity, *func),
524            Self::Transformer {
525                pattern,
526                update,
527                delete,
528            } => Value::transformer(arena, pattern, update, delete),
529            Self::Range(range) => Value::range_from(arena, range),
530            Self::Regex(regex) => arena.alloc(Value::Regex(regex.clone())),
531        }
532    }
533
534    pub fn clone_array_with_flags(&self, arena: &'a Bump, flags: ArrayFlags) -> &'a mut Value<'a> {
535        match *self {
536            Value::Array(ref array, _) => arena.alloc(Value::Array(array.clone(), flags)),
537            _ => panic!("Not an array"),
538        }
539    }
540
541    pub fn serialize(&'a self, pretty: bool) -> String {
542        if pretty {
543            let serializer = Serializer::new(PrettyFormatter::default(), false);
544            serializer.serialize(self).expect("Shouldn't fail")
545        } else {
546            let serializer = Serializer::new(DumpFormatter, false);
547            serializer.serialize(self).expect("Shouldn't fail")
548        }
549    }
550
551    // TODO: I don't have a good way to make modifications to values right now, so here's this absolutely
552    // no good, very bad, shouldn't exist reference transmuter :(
553    //
554    // This only exists for object transfomers, which specifically reach into existing values to make
555    // changes by updating and removing keys.
556    //
557    // Need to think up another way, but the whole evaluation pipeline is based on the immutability of Value,
558    // so something needs to give.
559    #[allow(invalid_reference_casting)]
560    pub fn __very_unsafe_make_mut(&'a self) -> &'a mut Value<'a> {
561        unsafe {
562            let const_ptr = self as *const Value<'a>;
563            let mut_ptr = const_ptr as *mut Value<'a>;
564            &mut *mut_ptr
565        }
566    }
567}