jsonata/value/
mod.rs

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