Skip to main content

bel/
objects.rs

1#[cfg(feature = "time")]
2use std::sync::LazyLock;
3use std::{
4    cmp::Ordering,
5    collections::HashMap,
6    convert::{Infallible, TryInto},
7    fmt::{Display, Formatter},
8    ops,
9    ops::Deref,
10    sync::Arc,
11};
12
13#[cfg(feature = "time")]
14use time::{DateTime, TimeZone};
15
16use crate::{
17    ExecutionError, Expression,
18    common::{
19        ast::{EntryExpr, Expr, operators},
20        value::CelVal,
21    },
22    context::Context,
23    functions::FunctionContext,
24};
25
26/// Timestamp values are limited to the range of values which can be serialized as a string:
27/// `["0001-01-01T00:00:00Z", "9999-12-31T23:59:59.999999999Z"]`. Since the max is a smaller
28/// and the min is a larger timestamp than what is possible to represent with [`DateTime`],
29/// we need to perform our own spec-compliant overflow checks.
30///
31/// https://github.com/google/cel-spec/blob/master/doc/langdef.md#overflow
32#[cfg(feature = "time")]
33static MAX_TIMESTAMP: LazyLock<DateTime> =
34    LazyLock::new(|| DateTime::from_parts(9999, 12, 31, 23, 59, 59, 999_999_999, TimeZone::UTC).unwrap());
35
36#[cfg(feature = "time")]
37static MIN_TIMESTAMP: LazyLock<DateTime> =
38    LazyLock::new(|| DateTime::from_parts(1, 1, 1, 0, 0, 0, 0, TimeZone::UTC).unwrap());
39
40#[derive(Debug, PartialEq, Clone)]
41// #[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
42pub struct Map {
43    pub map: Arc<HashMap<Key, Value>>,
44}
45
46impl PartialOrd for Map {
47    fn partial_cmp(&self, _: &Self) -> Option<Ordering> {
48        None
49    }
50}
51
52impl Map {
53    /// Returns a reference to the value corresponding to the key. Implicitly converts between int
54    /// and uint keys.
55    pub fn get(&self, key: &Key) -> Option<&Value> {
56        self.map.get(key)
57
58        // .or_else(|| {
59        //     // Also check keys that are cross type comparable.
60        //     let converted = match key {
61        //         Key::Int(k) => Key::Uint(u64::try_from(*k).ok()?),
62        //         // Key::Uint(k) => Key::Int(i64::try_from(*k).ok()?),
63        //         _ => return None,
64        //     };
65        //     self.map.get(&converted)
66        // })
67    }
68}
69
70#[derive(Debug, Eq, PartialEq, Hash, Ord, Clone, PartialOrd)]
71#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
72pub enum Key {
73    Int(i64),
74    // Uint(u64),
75    Bool(bool),
76    String(Arc<String>),
77}
78
79/// Implement conversions from primitive types to [`Key`]
80impl From<String> for Key {
81    fn from(v: String) -> Self {
82        Key::String(v.into())
83    }
84}
85
86impl From<Arc<String>> for Key {
87    fn from(v: Arc<String>) -> Self {
88        Key::String(v)
89    }
90}
91
92impl<'a> From<&'a str> for Key {
93    fn from(v: &'a str) -> Self {
94        Key::String(Arc::new(v.into()))
95    }
96}
97
98impl From<bool> for Key {
99    fn from(v: bool) -> Self {
100        Key::Bool(v)
101    }
102}
103
104impl From<i64> for Key {
105    fn from(v: i64) -> Self {
106        Key::Int(v)
107    }
108}
109
110// impl From<u64> for Key {
111//     fn from(v: u64) -> Self {
112//         Key::Uint(v)
113//     }
114// }
115
116impl serde::Serialize for Key {
117    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
118    where
119        S: serde::Serializer,
120    {
121        match self {
122            Key::Int(v) => v.serialize(serializer),
123            // Key::Uint(v) => v.serialize(serializer),
124            Key::Bool(v) => v.serialize(serializer),
125            Key::String(v) => v.serialize(serializer),
126        }
127    }
128}
129
130impl Display for Key {
131    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
132        match self {
133            Key::Int(v) => write!(f, "{v}"),
134            // Key::Uint(v) => write!(f, "{v}"),
135            Key::Bool(v) => write!(f, "{v}"),
136            Key::String(v) => write!(f, "{v}"),
137        }
138    }
139}
140
141/// Implement conversions from [`Key`] into [`Value`]
142impl TryInto<Key> for Value {
143    type Error = Value;
144
145    #[inline(always)]
146    fn try_into(self) -> Result<Key, Self::Error> {
147        match self {
148            Value::Int(v) => Ok(Key::Int(v)),
149            // Value::UInt(v) => Ok(Key::Uint(v)),
150            Value::String(v) => Ok(Key::String(v)),
151            Value::Bool(v) => Ok(Key::Bool(v)),
152            _ => Err(self),
153        }
154    }
155}
156
157// Implement conversion from HashMap<K, V> into CelMap
158impl<K: Into<Key>, V: Into<Value>> From<HashMap<K, V>> for Map {
159    fn from(map: HashMap<K, V>) -> Self {
160        let mut new_map = HashMap::with_capacity(map.len());
161        for (k, v) in map {
162            new_map.insert(k.into(), v.into());
163        }
164        Map {
165            map: Arc::new(new_map),
166        }
167    }
168}
169
170pub trait TryIntoValue {
171    type Error: core::error::Error + 'static + Send + Sync;
172    fn try_into_value(self) -> Result<Value, Self::Error>;
173}
174
175impl<T: serde::Serialize> TryIntoValue for T {
176    type Error = crate::ser::SerializationError;
177    fn try_into_value(self) -> Result<Value, Self::Error> {
178        crate::ser::to_value(self)
179    }
180}
181impl TryIntoValue for Value {
182    type Error = Infallible;
183    fn try_into_value(self) -> Result<Value, Self::Error> {
184        Ok(self)
185    }
186}
187
188#[derive(Debug, Clone)]
189// #[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
190pub enum Value {
191    List(Arc<Vec<Value>>),
192    Map(Map),
193
194    Function(Arc<String>, Option<Box<Value>>),
195
196    // Atoms
197    Int(i64),
198    // UInt(u64),
199    Float(f64),
200    String(Arc<String>),
201    Bytes(Arc<Vec<u8>>),
202    Bool(bool),
203    #[cfg(feature = "time")]
204    Duration(crate::duration::Duration),
205    #[cfg(feature = "time")]
206    Timestamp(DateTime),
207    #[cfg(feature = "regex")]
208    Regex(regex::Regex),
209    #[cfg(feature = "ip")]
210    Ip(ipnetwork::IpNetwork),
211    Null,
212}
213
214impl From<CelVal> for Value {
215    fn from(val: CelVal) -> Self {
216        match val {
217            CelVal::String(s) => Value::String(Arc::new(s)),
218            CelVal::Boolean(b) => Value::Bool(b),
219            CelVal::Int(i) => Value::Int(i),
220            // CelVal::UInt(u) => Value::UInt(u),
221            CelVal::Float(d) => Value::Float(d),
222            CelVal::Bytes(bytes) => Value::Bytes(Arc::new(bytes)),
223            CelVal::Null => Value::Null,
224            v => unimplemented!("{v:?}"),
225        }
226    }
227}
228
229#[derive(Clone, Copy, Debug)]
230pub enum ValueType {
231    List,
232    Map,
233    Function,
234    Int,
235    // UInt,
236    Float,
237    String,
238    Bytes,
239    Bool,
240    Duration,
241    Timestamp,
242    Regex,
243    Ip,
244    Null,
245}
246
247impl Display for ValueType {
248    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
249        match self {
250            ValueType::List => write!(f, "list"),
251            ValueType::Map => write!(f, "map"),
252            ValueType::Function => write!(f, "function"),
253            ValueType::Int => write!(f, "int"),
254            // ValueType::UInt => write!(f, "uint"),
255            ValueType::Float => write!(f, "float"),
256            ValueType::String => write!(f, "string"),
257            ValueType::Bytes => write!(f, "bytes"),
258            ValueType::Bool => write!(f, "bool"),
259            ValueType::Duration => write!(f, "duration"),
260            ValueType::Timestamp => write!(f, "timestamp"),
261            ValueType::Regex => write!(f, "regex"),
262            ValueType::Ip => write!(f, "ip"),
263            ValueType::Null => write!(f, "null"),
264        }
265    }
266}
267
268impl Value {
269    pub fn type_of(&self) -> ValueType {
270        match self {
271            Value::List(_) => ValueType::List,
272            Value::Map(_) => ValueType::Map,
273            Value::Function(_, _) => ValueType::Function,
274            Value::Int(_) => ValueType::Int,
275            // Value::UInt(_) => ValueType::UInt,
276            Value::Float(_) => ValueType::Float,
277            Value::String(_) => ValueType::String,
278            Value::Bytes(_) => ValueType::Bytes,
279            Value::Bool(_) => ValueType::Bool,
280            #[cfg(feature = "time")]
281            Value::Duration(_) => ValueType::Duration,
282            #[cfg(feature = "time")]
283            Value::Timestamp(_) => ValueType::Timestamp,
284            #[cfg(feature = "regex")]
285            Value::Regex(_) => ValueType::Regex,
286            #[cfg(feature = "ip")]
287            Value::Ip(_) => ValueType::Ip,
288            Value::Null => ValueType::Null,
289        }
290    }
291
292    pub fn error_expected_type(&self, expected: ValueType) -> ExecutionError {
293        ExecutionError::UnexpectedType {
294            got: self.type_of().to_string(),
295            want: expected.to_string(),
296        }
297    }
298}
299
300impl From<&Value> for Value {
301    fn from(value: &Value) -> Self {
302        value.clone()
303    }
304}
305
306impl PartialEq for Value {
307    fn eq(&self, other: &Self) -> bool {
308        match (self, other) {
309            (Value::Map(a), Value::Map(b)) => a == b,
310            (Value::List(a), Value::List(b)) => a == b,
311            (Value::Function(a1, a2), Value::Function(b1, b2)) => a1 == b1 && a2 == b2,
312            (Value::Int(a), Value::Int(b)) => a == b,
313            // (Value::UInt(a), Value::UInt(b)) => a == b,
314            (Value::Float(a), Value::Float(b)) => a == b,
315            (Value::String(a), Value::String(b)) => a == b,
316            (Value::Bytes(a), Value::Bytes(b)) => a == b,
317            (Value::Bool(a), Value::Bool(b)) => a == b,
318            (Value::Null, Value::Null) => true,
319            #[cfg(feature = "time")]
320            (Value::Duration(a), Value::Duration(b)) => a == b,
321            #[cfg(feature = "time")]
322            (Value::Timestamp(a), Value::Timestamp(b)) => a == b,
323            // Allow different numeric types to be compared without explicit casting.
324            // (Value::Int(a), Value::UInt(b)) => a
325            //     .to_owned()
326            //     .try_into()
327            //     .map(|a: u64| a == *b)
328            //     .unwrap_or(false),
329            (Value::Int(a), Value::Float(b)) => (*a as f64) == *b,
330            // (Value::UInt(a), Value::Int(b)) => a
331            //     .to_owned()
332            //     .try_into()
333            //     .map(|a: i64| a == *b)
334            //     .unwrap_or(false),
335            // (Value::UInt(a), Value::Float(b)) => (*a as f64) == *b,
336            (Value::Float(a), Value::Int(b)) => *a == (*b as f64),
337            // (Value::Float(a), Value::UInt(b)) => *a == (*b as f64),
338            #[cfg(feature = "ip")]
339            (Value::Ip(a), Value::Ip(b)) => a == b,
340            (_, _) => false,
341        }
342    }
343}
344
345impl Eq for Value {}
346
347impl PartialOrd for Value {
348    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
349        match (self, other) {
350            (Value::Int(a), Value::Int(b)) => Some(a.cmp(b)),
351            // (Value::UInt(a), Value::UInt(b)) => Some(a.cmp(b)),
352            (Value::Float(a), Value::Float(b)) => a.partial_cmp(b),
353            (Value::String(a), Value::String(b)) => Some(a.cmp(b)),
354            (Value::Bool(a), Value::Bool(b)) => Some(a.cmp(b)),
355            (Value::Null, Value::Null) => Some(Ordering::Equal),
356            #[cfg(feature = "time")]
357            (Value::Duration(a), Value::Duration(b)) => Some(a.cmp(b)),
358            #[cfg(feature = "time")]
359            (Value::Timestamp(a), Value::Timestamp(b)) => Some(a.cmp(b)),
360            // Allow different numeric types to be compared without explicit casting.
361            // (Value::Int(a), Value::UInt(b)) => Some(
362            //     a.to_owned()
363            //         .try_into()
364            //         .map(|a: u64| a.cmp(b))
365            //         // If the i64 doesn't fit into a u64 it must be less than 0.
366            //         .unwrap_or(Ordering::Less),
367            // ),
368            (Value::Int(a), Value::Float(b)) => (*a as f64).partial_cmp(b),
369            // (Value::UInt(a), Value::Int(b)) => Some(
370            //     a.to_owned()
371            //         .try_into()
372            //         .map(|a: i64| a.cmp(b))
373            //         // If the u64 doesn't fit into a i64 it must be greater than i64::MAX.
374            //         .unwrap_or(Ordering::Greater),
375            // ),
376            // (Value::UInt(a), Value::Float(b)) => (*a as f64).partial_cmp(b),
377            (Value::Float(a), Value::Int(b)) => a.partial_cmp(&(*b as f64)),
378            // (Value::Float(a), Value::UInt(b)) => a.partial_cmp(&(*b as f64)),
379            #[cfg(feature = "ip")]
380            (Value::Ip(a), Value::Ip(b)) => Some(a.cmp(b)),
381            _ => None,
382        }
383    }
384}
385
386impl From<&Key> for Value {
387    fn from(value: &Key) -> Self {
388        match value {
389            Key::Int(v) => Value::Int(*v),
390            // Key::Uint(v) => Value::UInt(*v),
391            Key::Bool(v) => Value::Bool(*v),
392            Key::String(v) => Value::String(v.clone()),
393        }
394    }
395}
396
397impl From<Key> for Value {
398    fn from(value: Key) -> Self {
399        match value {
400            Key::Int(v) => Value::Int(v),
401            // Key::Uint(v) => Value::UInt(v),
402            Key::Bool(v) => Value::Bool(v),
403            Key::String(v) => Value::String(v),
404        }
405    }
406}
407
408impl From<&Key> for Key {
409    fn from(key: &Key) -> Self {
410        key.clone()
411    }
412}
413
414// Convert Vec<T> to Value
415impl<T: Into<Value>> From<Vec<T>> for Value {
416    fn from(v: Vec<T>) -> Self {
417        Value::List(v.into_iter().map(|v| v.into()).collect::<Vec<_>>().into())
418    }
419}
420
421// Convert Vec<u8> to Value
422impl From<Vec<u8>> for Value {
423    fn from(v: Vec<u8>) -> Self {
424        Value::Bytes(v.into())
425    }
426}
427
428// Convert String to Value
429impl From<String> for Value {
430    fn from(v: String) -> Self {
431        Value::String(v.into())
432    }
433}
434
435impl From<&str> for Value {
436    fn from(v: &str) -> Self {
437        Value::String(v.to_string().into())
438    }
439}
440
441// Convert Option<T> to Value
442impl<T: Into<Value>> From<Option<T>> for Value {
443    fn from(v: Option<T>) -> Self {
444        match v {
445            Some(v) => v.into(),
446            None => Value::Null,
447        }
448    }
449}
450
451// Convert HashMap<K, V> to Value
452impl<K: Into<Key>, V: Into<Value>> From<HashMap<K, V>> for Value {
453    fn from(v: HashMap<K, V>) -> Self {
454        Value::Map(v.into())
455    }
456}
457
458impl From<ExecutionError> for ResolveResult {
459    fn from(value: ExecutionError) -> Self {
460        Err(value)
461    }
462}
463
464pub type ResolveResult = Result<Value, ExecutionError>;
465
466impl From<Value> for ResolveResult {
467    fn from(value: Value) -> Self {
468        Ok(value)
469    }
470}
471
472impl Value {
473    pub fn resolve_all(expr: &[Expression], ctx: &Context) -> ResolveResult {
474        let mut res = Vec::with_capacity(expr.len());
475        for expr in expr {
476            res.push(Value::resolve(expr, ctx)?);
477        }
478        Ok(Value::List(res.into()))
479    }
480
481    #[inline(always)]
482    pub fn resolve(expr: &Expression, ctx: &Context) -> ResolveResult {
483        match &expr.expr {
484            Expr::Literal(val) => Ok(val.clone().into()),
485            Expr::Call(call) => {
486                if call.args.len() == 3 && call.func_name == operators::CONDITIONAL {
487                    let cond = Value::resolve(&call.args[0], ctx)?;
488                    return if cond.to_bool()? {
489                        Value::resolve(&call.args[1], ctx)
490                    } else {
491                        Value::resolve(&call.args[2], ctx)
492                    };
493                }
494                if call.args.len() == 2 {
495                    match call.func_name.as_str() {
496                        operators::ADD => {
497                            return Value::resolve(&call.args[0], ctx)? + Value::resolve(&call.args[1], ctx)?;
498                        }
499                        operators::SUBSTRACT => {
500                            return Value::resolve(&call.args[0], ctx)? - Value::resolve(&call.args[1], ctx)?;
501                        }
502                        operators::DIVIDE => {
503                            return Value::resolve(&call.args[0], ctx)? / Value::resolve(&call.args[1], ctx)?;
504                        }
505                        operators::MULTIPLY => {
506                            return Value::resolve(&call.args[0], ctx)? * Value::resolve(&call.args[1], ctx)?;
507                        }
508                        operators::MODULO => {
509                            return Value::resolve(&call.args[0], ctx)? % Value::resolve(&call.args[1], ctx)?;
510                        }
511                        operators::EQUALS => {
512                            return Value::Bool(
513                                Value::resolve(&call.args[0], ctx)?.eq(&Value::resolve(&call.args[1], ctx)?),
514                            )
515                            .into();
516                        }
517                        operators::NOT_EQUALS => {
518                            return Value::Bool(
519                                Value::resolve(&call.args[0], ctx)?.ne(&Value::resolve(&call.args[1], ctx)?),
520                            )
521                            .into();
522                        }
523                        operators::LESS => {
524                            let left = Value::resolve(&call.args[0], ctx)?;
525                            let right = Value::resolve(&call.args[1], ctx)?;
526                            return Value::Bool(
527                                left.partial_cmp(&right)
528                                    .ok_or(ExecutionError::ValuesNotComparable(left, right))?
529                                    == Ordering::Less,
530                            )
531                            .into();
532                        }
533                        operators::LESS_EQUALS => {
534                            let left = Value::resolve(&call.args[0], ctx)?;
535                            let right = Value::resolve(&call.args[1], ctx)?;
536                            return Value::Bool(
537                                left.partial_cmp(&right)
538                                    .ok_or(ExecutionError::ValuesNotComparable(left, right))?
539                                    != Ordering::Greater,
540                            )
541                            .into();
542                        }
543                        operators::GREATER => {
544                            let left = Value::resolve(&call.args[0], ctx)?;
545                            let right = Value::resolve(&call.args[1], ctx)?;
546                            return Value::Bool(
547                                left.partial_cmp(&right)
548                                    .ok_or(ExecutionError::ValuesNotComparable(left, right))?
549                                    == Ordering::Greater,
550                            )
551                            .into();
552                        }
553                        operators::GREATER_EQUALS => {
554                            let left = Value::resolve(&call.args[0], ctx)?;
555                            let right = Value::resolve(&call.args[1], ctx)?;
556                            return Value::Bool(
557                                left.partial_cmp(&right)
558                                    .ok_or(ExecutionError::ValuesNotComparable(left, right))?
559                                    != Ordering::Less,
560                            )
561                            .into();
562                        }
563                        // operators::IN => {
564                        //     let left = Value::resolve(&call.args[0], ctx)?;
565                        //     let right = Value::resolve(&call.args[1], ctx)?;
566                        //     match (left, right) {
567                        //         (Value::String(l), Value::String(r)) => {
568                        //             return Value::Bool(r.contains(&*l)).into();
569                        //         }
570                        //         (any, Value::List(v)) => {
571                        //             return Value::Bool(v.contains(&any)).into();
572                        //         }
573                        //         (any, Value::Map(m)) => match any.try_into() {
574                        //             Ok(key) => return Value::Bool(m.map.contains_key(&key)).into(),
575                        //             Err(_) => return Value::Bool(false).into(),
576                        //         },
577                        //         (left, right) => {
578                        //             Err(ExecutionError::ValuesNotComparable(left, right))?
579                        //         }
580                        //     }
581                        // }
582                        operators::LOGICAL_OR => {
583                            let left = Value::resolve(&call.args[0], ctx)?;
584                            return if left.to_bool()? {
585                                left.into()
586                            } else {
587                                Value::resolve(&call.args[1], ctx)
588                            };
589                        }
590                        operators::LOGICAL_AND => {
591                            let left = Value::resolve(&call.args[0], ctx)?;
592                            return if !left.to_bool()? {
593                                Value::Bool(false)
594                            } else {
595                                let right = Value::resolve(&call.args[1], ctx)?;
596                                Value::Bool(right.to_bool()?)
597                            }
598                            .into();
599                        }
600                        operators::INDEX => {
601                            let value = Value::resolve(&call.args[0], ctx)?;
602                            let idx = Value::resolve(&call.args[1], ctx)?;
603                            return match (value, idx) {
604                                (Value::List(items), Value::Int(idx)) => {
605                                    items.get(idx as usize).cloned().unwrap_or(Value::Null).into()
606                                }
607                                (Value::String(str), Value::Int(idx)) => {
608                                    match str.get(idx as usize..(idx + 1) as usize) {
609                                        None => Ok(Value::Null),
610                                        Some(str) => Ok(Value::String(str.to_string().into())),
611                                    }
612                                }
613                                (Value::Map(map), Value::String(property)) => {
614                                    map.get(&property.into()).cloned().unwrap_or(Value::Null).into()
615                                }
616                                (Value::Map(map), Value::Bool(property)) => {
617                                    map.get(&property.into()).cloned().unwrap_or(Value::Null).into()
618                                }
619                                (Value::Map(map), Value::Int(property)) => {
620                                    map.get(&property.into()).cloned().unwrap_or(Value::Null).into()
621                                }
622                                // (Value::Map(map), Value::UInt(property)) => map
623                                //     .get(&property.into())
624                                //     .cloned()
625                                //     .unwrap_or(Value::Null)
626                                //     .into(),
627                                (Value::Map(_), index) => Err(ExecutionError::UnsupportedMapIndex(index)),
628                                (Value::List(_), index) => Err(ExecutionError::UnsupportedListIndex(index)),
629                                (value, index) => Err(ExecutionError::UnsupportedIndex(value, index)),
630                            };
631                        }
632                        _ => (),
633                    }
634                }
635                if call.args.len() == 1 {
636                    let expr = Value::resolve(&call.args[0], ctx)?;
637                    match call.func_name.as_str() {
638                        operators::LOGICAL_NOT => return Ok(Value::Bool(!expr.to_bool()?)),
639                        operators::NEGATE => {
640                            return match expr {
641                                Value::Int(i) => Ok(Value::Int(-i)),
642                                Value::Float(f) => Ok(Value::Float(-f)),
643                                value => Err(ExecutionError::UnsupportedUnaryOperator("minus", value)),
644                            };
645                        }
646                        operators::NOT_STRICTLY_FALSE => {
647                            return match expr {
648                                Value::Bool(b) => Ok(Value::Bool(b)),
649                                _ => Ok(Value::Bool(true)),
650                            };
651                        }
652                        _ => (),
653                    }
654                }
655                let func = ctx
656                    .get_function(call.func_name.as_str())
657                    .ok_or_else(|| ExecutionError::UndeclaredReference(call.func_name.clone().into()))?;
658                match &call.target {
659                    None => {
660                        let mut ctx = FunctionContext::new(call.func_name.clone().into(), None, ctx, call.args.clone());
661                        (func)(&mut ctx)
662                    }
663                    Some(target) => {
664                        let mut ctx = FunctionContext::new(
665                            call.func_name.clone().into(),
666                            Some(Value::resolve(target, ctx)?),
667                            ctx,
668                            call.args.clone(),
669                        );
670                        (func)(&mut ctx)
671                    }
672                }
673            }
674            Expr::Ident(name) => ctx.get_variable(name),
675            Expr::Select(select) => {
676                let left = Value::resolve(select.operand.deref(), ctx)?;
677                if select.test {
678                    match &left {
679                        Value::Map(map) => {
680                            for key in map.map.deref().keys() {
681                                if key.to_string().eq(&select.field) {
682                                    return Ok(Value::Bool(true));
683                                }
684                            }
685                            Ok(Value::Bool(false))
686                        }
687                        _ => Ok(Value::Bool(false)),
688                    }
689                } else {
690                    left.member(&select.field)
691                }
692            }
693            Expr::List(list_expr) => {
694                let list = list_expr
695                    .elements
696                    .iter()
697                    .map(|i| Value::resolve(i, ctx))
698                    .collect::<Result<Vec<_>, _>>()?;
699                Value::List(list.into()).into()
700            }
701            Expr::Map(map_expr) => {
702                let mut map = HashMap::with_capacity(map_expr.entries.len());
703                for entry in map_expr.entries.iter() {
704                    let (k, v) = match &entry.expr {
705                        EntryExpr::StructField(_) => panic!("WAT?"),
706                        EntryExpr::MapEntry(e) => (&e.key, &e.value),
707                    };
708                    let key = Value::resolve(k, ctx)?
709                        .try_into()
710                        .map_err(ExecutionError::UnsupportedKeyType)?;
711                    let value = Value::resolve(v, ctx)?;
712                    map.insert(key, value);
713                }
714                Ok(Value::Map(Map {
715                    map: Arc::from(map),
716                }))
717            }
718            Expr::Comprehension(comprehension) => {
719                let accu_init = Value::resolve(&comprehension.accu_init, ctx)?;
720                let iter = Value::resolve(&comprehension.iter_range, ctx)?;
721                let mut ctx = ctx.new_inner_scope();
722                ctx.add_variable(&comprehension.accu_var, accu_init)
723                    .expect("Failed to add accu variable");
724
725                match iter {
726                    Value::List(items) => {
727                        for item in items.deref() {
728                            if !Value::resolve(&comprehension.loop_cond, &ctx)?.to_bool()? {
729                                break;
730                            }
731                            ctx.add_variable_from_value(&comprehension.iter_var, item.clone());
732                            let accu = Value::resolve(&comprehension.loop_step, &ctx)?;
733                            ctx.add_variable_from_value(&comprehension.accu_var, accu);
734                        }
735                    }
736                    Value::Map(map) => {
737                        for key in map.map.deref().keys() {
738                            if !Value::resolve(&comprehension.loop_cond, &ctx)?.to_bool()? {
739                                break;
740                            }
741                            ctx.add_variable_from_value(&comprehension.iter_var, key.clone());
742                            let accu = Value::resolve(&comprehension.loop_step, &ctx)?;
743                            ctx.add_variable_from_value(&comprehension.accu_var, accu);
744                        }
745                    }
746                    t => todo!("Support {t:?}"),
747                }
748                Value::resolve(&comprehension.result, &ctx)
749            }
750            Expr::Struct(_) => todo!("Support structs!"),
751            Expr::Unspecified => panic!("Can't evaluate Unspecified Expr"),
752        }
753    }
754
755    // >> a(b)
756    // Member(Ident("a"),
757    //        FunctionCall([Ident("b")]))
758    // >> a.b(c)
759    // Member(Member(Ident("a"),
760    //               Attribute("b")),
761    //        FunctionCall([Ident("c")]))
762
763    fn member(self, name: &str) -> ResolveResult {
764        // todo! Ideally we would avoid creating a String just to create a Key for lookup in the
765        // map, but this would require something like the `hashbrown` crate's `Equivalent` trait.
766        let name: Arc<String> = name.to_owned().into();
767
768        // This will always either be because we're trying to access
769        // a property on self, or a method on self.
770        let child = match self {
771            Value::Map(ref m) => m.map.get(&name.clone().into()).cloned(),
772            _ => None,
773        };
774
775        // If the property is both an attribute and a method, then we
776        // give priority to the property. Maybe we can implement lookahead
777        // to see if the next token is a function call?
778        if let Some(child) = child {
779            child.into()
780        } else {
781            ExecutionError::NoSuchKey(name.clone()).into()
782        }
783    }
784
785    #[inline(always)]
786    fn to_bool(&self) -> Result<bool, ExecutionError> {
787        match self {
788            Value::Bool(v) => Ok(*v),
789            _ => Err(ExecutionError::NoSuchOverload),
790        }
791    }
792}
793
794impl ops::Add<Value> for Value {
795    type Output = ResolveResult;
796
797    #[inline(always)]
798    fn add(self, rhs: Value) -> Self::Output {
799        match (self, rhs) {
800            (Value::Int(l), Value::Int(r)) => l
801                .checked_add(r)
802                .ok_or(ExecutionError::Overflow("add", l.into(), r.into()))
803                .map(Value::Int),
804
805            // (Value::UInt(l), Value::UInt(r)) => l
806            //     .checked_add(r)
807            //     .ok_or(ExecutionError::Overflow("add", l.into(), r.into()))
808            //     .map(Value::UInt),
809            (Value::Float(l), Value::Float(r)) => Value::Float(l + r).into(),
810
811            (Value::List(mut l), Value::List(mut r)) => {
812                {
813                    // If this is the only reference to `l`, we can append to it in place.
814                    // `l` is replaced with a clone otherwise.
815                    let l = Arc::make_mut(&mut l);
816
817                    // Likewise, if this is the only reference to `r`, we can move its values
818                    // instead of cloning them.
819                    match Arc::get_mut(&mut r) {
820                        Some(r) => l.append(r),
821                        None => l.extend(r.iter().cloned()),
822                    }
823                }
824
825                Ok(Value::List(l))
826            }
827            (Value::String(mut l), Value::String(r)) => {
828                // If this is the only reference to `l`, we can append to it in place.
829                // `l` is replaced with a clone otherwise.
830                Arc::make_mut(&mut l).push_str(&r);
831                Ok(Value::String(l))
832            }
833            #[cfg(feature = "time")]
834            (Value::Duration(l), Value::Duration(r)) => l
835                .checked_add(r)
836                .ok_or(ExecutionError::Overflow("add", l.into(), r.into()))
837                .map(Value::Duration),
838            #[cfg(feature = "time")]
839            (Value::Timestamp(l), Value::Duration(r)) => checked_op(TsOp::Add, &l, &r),
840            #[cfg(feature = "time")]
841            (Value::Duration(l), Value::Timestamp(r)) => checked_op(TsOp::Add, &r, &l),
842            (left, right) => Err(ExecutionError::UnsupportedBinaryOperator("add", left, right)),
843        }
844    }
845}
846
847impl ops::Sub<Value> for Value {
848    type Output = ResolveResult;
849
850    #[inline(always)]
851    fn sub(self, rhs: Value) -> Self::Output {
852        match (self, rhs) {
853            (Value::Int(l), Value::Int(r)) => l
854                .checked_sub(r)
855                .ok_or(ExecutionError::Overflow("sub", l.into(), r.into()))
856                .map(Value::Int),
857
858            // (Value::UInt(l), Value::UInt(r)) => l
859            //     .checked_sub(r)
860            //     .ok_or(ExecutionError::Overflow("sub", l.into(), r.into()))
861            //     .map(Value::UInt),
862            (Value::Float(l), Value::Float(r)) => Value::Float(l - r).into(),
863
864            #[cfg(feature = "time")]
865            (Value::Duration(l), Value::Duration(r)) => l
866                .checked_sub(r)
867                .ok_or(ExecutionError::Overflow("sub", l.into(), r.into()))
868                .map(Value::Duration),
869            #[cfg(feature = "time")]
870            (Value::Timestamp(l), Value::Duration(r)) => checked_op(TsOp::Sub, &l, &r),
871            #[cfg(feature = "time")]
872            (Value::Timestamp(l), Value::Timestamp(r)) => {
873                Value::Duration(crate::duration::Duration::from_nanos(l.unix_nanos() - r.unix_nanos())).into()
874            }
875            (left, right) => Err(ExecutionError::UnsupportedBinaryOperator("sub", left, right)),
876        }
877    }
878}
879
880impl ops::Div<Value> for Value {
881    type Output = ResolveResult;
882
883    #[inline(always)]
884    fn div(self, rhs: Value) -> Self::Output {
885        match (self, rhs) {
886            (Value::Int(l), Value::Int(r)) => {
887                if r == 0 {
888                    Err(ExecutionError::DivisionByZero(l.into()))
889                } else {
890                    l.checked_div(r)
891                        .ok_or(ExecutionError::Overflow("div", l.into(), r.into()))
892                        .map(Value::Int)
893                }
894            }
895
896            // (Value::UInt(l), Value::UInt(r)) => l
897            //     .checked_div(r)
898            //     .ok_or(ExecutionError::DivisionByZero(l.into()))
899            //     .map(Value::UInt),
900            (Value::Float(l), Value::Float(r)) => Value::Float(l / r).into(),
901
902            (left, right) => Err(ExecutionError::UnsupportedBinaryOperator("div", left, right)),
903        }
904    }
905}
906
907impl ops::Mul<Value> for Value {
908    type Output = ResolveResult;
909
910    #[inline(always)]
911    fn mul(self, rhs: Value) -> Self::Output {
912        match (self, rhs) {
913            (Value::Int(l), Value::Int(r)) => l
914                .checked_mul(r)
915                .ok_or(ExecutionError::Overflow("mul", l.into(), r.into()))
916                .map(Value::Int),
917
918            // (Value::UInt(l), Value::UInt(r)) => l
919            //     .checked_mul(r)
920            //     .ok_or(ExecutionError::Overflow("mul", l.into(), r.into()))
921            //     .map(Value::UInt),
922            (Value::Float(l), Value::Float(r)) => Value::Float(l * r).into(),
923
924            (left, right) => Err(ExecutionError::UnsupportedBinaryOperator("mul", left, right)),
925        }
926    }
927}
928
929impl ops::Rem<Value> for Value {
930    type Output = ResolveResult;
931
932    #[inline(always)]
933    fn rem(self, rhs: Value) -> Self::Output {
934        match (self, rhs) {
935            (Value::Int(l), Value::Int(r)) => {
936                if r == 0 {
937                    Err(ExecutionError::RemainderByZero(l.into()))
938                } else {
939                    l.checked_rem(r)
940                        .ok_or(ExecutionError::Overflow("rem", l.into(), r.into()))
941                        .map(Value::Int)
942                }
943            }
944
945            // (Value::UInt(l), Value::UInt(r)) => l
946            //     .checked_rem(r)
947            //     .ok_or(ExecutionError::RemainderByZero(l.into()))
948            //     .map(Value::UInt),
949            (left, right) => Err(ExecutionError::UnsupportedBinaryOperator("rem", left, right)),
950        }
951    }
952}
953
954/// Op represents a binary arithmetic operation supported on a timestamp
955///
956#[cfg(feature = "time")]
957enum TsOp {
958    Add,
959    Sub,
960}
961
962#[cfg(feature = "time")]
963impl TsOp {
964    fn str(&self) -> &'static str {
965        match self {
966            TsOp::Add => "add",
967            TsOp::Sub => "sub",
968        }
969    }
970}
971
972/// Performs a checked arithmetic operation [`TsOp`] on a timestamp and a duration and ensures that
973/// the resulting timestamp does not overflow the data type internal limits, as well as the timestamp
974/// limits defined in the cel-spec. See [`MAX_TIMESTAMP`] and [`MIN_TIMESTAMP`] for more details.
975#[cfg(feature = "time")]
976fn checked_op(op: TsOp, lhs: &DateTime, rhs: &crate::duration::Duration) -> ResolveResult {
977    // Add lhs and rhs together, checking for data type overflow.
978    let delta = rhs.as_nanos();
979    let nanos = match op {
980        TsOp::Add => lhs.unix_nanos().checked_add(delta),
981        TsOp::Sub => lhs.unix_nanos().checked_sub(delta),
982    }
983    .ok_or(ExecutionError::Overflow(op.str(), (*lhs).into(), (*rhs).into()))?;
984
985    let result = DateTime::from_unix_nanos(nanos)
986        .map_err(|_| ExecutionError::Overflow(op.str(), (*lhs).into(), (*rhs).into()))?;
987
988    // Check for cel-spec limits.
989    if result > *MAX_TIMESTAMP || result < *MIN_TIMESTAMP {
990        Err(ExecutionError::Overflow(op.str(), (*lhs).into(), (*rhs).into()))
991    } else {
992        Value::Timestamp(result).into()
993    }
994}
995
996#[cfg(test)]
997mod tests {
998    use std::{collections::HashMap, sync::Arc};
999
1000    use crate::{Context, ExecutionError, Program, Value, objects::Key};
1001
1002    #[test]
1003    fn test_indexed_map_access() {
1004        let mut context = Context::default();
1005        let mut headers = HashMap::new();
1006        headers.insert("Content-Type", "application/json".to_string());
1007        context.add_variable_from_value("headers", headers);
1008
1009        let program = Program::compile("headers[\"Content-Type\"]").unwrap();
1010        let value = program.execute(&context).unwrap();
1011        assert_eq!(value, "application/json".into());
1012    }
1013
1014    #[test]
1015    fn test_numeric_map_access() {
1016        let mut context = Context::default();
1017        let mut numbers = HashMap::new();
1018        numbers.insert(Key::Int(1), "one".to_string());
1019        context.add_variable_from_value("numbers", numbers);
1020
1021        let program = Program::compile("numbers[1]").unwrap();
1022        let value = program.execute(&context).unwrap();
1023        assert_eq!(value, "one".into());
1024    }
1025
1026    #[test]
1027    fn test_heterogeneous_compare() {
1028        let context = Context::default();
1029
1030        // let program = Program::compile("1 < Uint(2)").unwrap();
1031        // let value = program.execute(&context).unwrap();
1032        // assert_eq!(value, true.into());
1033
1034        let program = Program::compile("1 < 1.1").unwrap();
1035        let value = program.execute(&context).unwrap();
1036        assert_eq!(value, true.into());
1037
1038        // let program = Program::compile("Uint(0) > -10").unwrap();
1039        // let value = program.execute(&context).unwrap();
1040        // assert_eq!(
1041        //     value,
1042        //     true.into(),
1043        //     "negative signed ints should be less than uints"
1044        // );
1045    }
1046
1047    #[test]
1048    fn test_float_compare() {
1049        let context = Context::default();
1050
1051        let program = Program::compile("1.0 > 0.0").unwrap();
1052        let value = program.execute(&context).unwrap();
1053        assert_eq!(value, true.into());
1054
1055        let program = Program::compile(r#"Float("NaN") == Float("NaN")"#).unwrap();
1056        let value = program.execute(&context).unwrap();
1057        assert_eq!(value, false.into(), "NaN should not equal itself");
1058
1059        let program = Program::compile(r#"1.0 > Float("NaN")"#).unwrap();
1060        let result = program.execute(&context);
1061        assert!(result.is_err(), "NaN should not be comparable with inequality operators");
1062    }
1063
1064    #[test]
1065    fn test_invalid_compare() {
1066        let context = Context::default();
1067
1068        let program = Program::compile("{} == []").unwrap();
1069        let value = program.execute(&context).unwrap();
1070        assert_eq!(value, false.into());
1071    }
1072
1073    #[test]
1074    fn test_size_fn_var() {
1075        let program = Program::compile("length(requests) + size == 5").unwrap();
1076        let mut context = Context::default();
1077        let requests = vec![Value::Int(42), Value::Int(42)];
1078        context
1079            .add_variable("requests", Value::List(Arc::new(requests)))
1080            .unwrap();
1081        context.add_variable("size", Value::Int(3)).unwrap();
1082        assert_eq!(program.execute(&context).unwrap(), Value::Bool(true));
1083    }
1084
1085    fn test_execution_error(program: &str, expected: ExecutionError) {
1086        let program = Program::compile(program).unwrap();
1087        let result = program.execute(&Context::default());
1088        assert_eq!(result.unwrap_err(), expected);
1089    }
1090
1091    #[test]
1092    fn test_invalid_sub() {
1093        test_execution_error(
1094            r#""foo" - 10"#,
1095            ExecutionError::UnsupportedBinaryOperator("sub", "foo".into(), Value::Int(10)),
1096        );
1097    }
1098
1099    #[test]
1100    fn test_invalid_add() {
1101        test_execution_error(
1102            r#""foo" + 10"#,
1103            ExecutionError::UnsupportedBinaryOperator("add", "foo".into(), Value::Int(10)),
1104        );
1105    }
1106
1107    #[test]
1108    fn test_invalid_div() {
1109        test_execution_error(
1110            r#""foo" / 10"#,
1111            ExecutionError::UnsupportedBinaryOperator("div", "foo".into(), Value::Int(10)),
1112        );
1113    }
1114
1115    #[test]
1116    fn test_invalid_rem() {
1117        test_execution_error(
1118            r#""foo" % 10"#,
1119            ExecutionError::UnsupportedBinaryOperator("rem", "foo".into(), Value::Int(10)),
1120        );
1121    }
1122
1123    #[test]
1124    fn out_of_bound_list_access() {
1125        let program = Program::compile("list[10]").unwrap();
1126        let mut context = Context::default();
1127        context.add_variable("list", Value::List(Arc::new(vec![]))).unwrap();
1128        let result = program.execute(&context);
1129        assert_eq!(result.unwrap(), Value::Null);
1130    }
1131
1132    #[test]
1133    fn reference_to_value() {
1134        let test = "example".to_string();
1135        let direct: Value = test.as_str().into();
1136        assert_eq!(direct, Value::String(Arc::new(String::from("example"))));
1137
1138        let vec = vec![test.as_str()];
1139        let indirect: Value = vec.into();
1140        assert_eq!(
1141            indirect,
1142            Value::List(Arc::new(vec![Value::String(Arc::new(String::from("example")))]))
1143        );
1144    }
1145
1146    #[test]
1147    fn test_short_circuit_and() {
1148        let mut context = Context::default();
1149        let data: HashMap<String, String> = HashMap::new();
1150        context.add_variable_from_value("data", data);
1151
1152        let program = Program::compile("has(data.x) && data.x.starts_with(\"foo\")").unwrap();
1153        let value = program.execute(&context);
1154        println!("{value:?}");
1155        assert!(value.is_ok(), "The AND expression should support short-circuit evaluation.");
1156    }
1157
1158    #[test]
1159    fn invalid_int_math() {
1160        use ExecutionError::*;
1161
1162        let cases = [
1163            ("1 / 0", DivisionByZero(1.into())),
1164            ("1 % 0", RemainderByZero(1.into())),
1165            (&format!("{} + 1", i64::MAX), Overflow("add", i64::MAX.into(), 1.into())),
1166            (&format!("{} - 1", i64::MIN), Overflow("sub", i64::MIN.into(), 1.into())),
1167            (&format!("{} * 2", i64::MAX), Overflow("mul", i64::MAX.into(), 2.into())),
1168            (&format!("{} / -1", i64::MIN), Overflow("div", i64::MIN.into(), (-1).into())),
1169            (&format!("{} % -1", i64::MIN), Overflow("rem", i64::MIN.into(), (-1).into())),
1170        ];
1171
1172        for (expr, err) in cases {
1173            test_execution_error(expr, err);
1174        }
1175    }
1176
1177    // #[test]
1178    // fn invalid_uint_math() {
1179    //     use ExecutionError::*;
1180
1181    //     let cases = [
1182    //         ("1u / 0u", DivisionByZero(1u64.into())),
1183    //         ("1u % 0u", RemainderByZero(1u64.into())),
1184    //         (
1185    //             &format!("{}u + 1u", u64::MAX),
1186    //             Overflow("add", u64::MAX.into(), 1u64.into()),
1187    //         ),
1188    //         ("0u - 1u", Overflow("sub", 0u64.into(), 1u64.into())),
1189    //         (
1190    //             &format!("{}u * 2u", u64::MAX),
1191    //             Overflow("mul", u64::MAX.into(), 2u64.into()),
1192    //         ),
1193    //     ];
1194
1195    //     for (expr, err) in cases {
1196    //         test_execution_error(expr, err);
1197    //     }
1198    // }
1199
1200    #[test]
1201    fn test_function_identifier() {
1202        fn with(
1203            ftx: &crate::FunctionContext,
1204            crate::extractors::This(this): crate::extractors::This<Value>,
1205            ident: crate::extractors::Identifier,
1206            expr: crate::parser::Expression,
1207        ) -> crate::ResolveResult {
1208            let mut ptx = ftx.ptx.new_inner_scope();
1209            ptx.add_variable_from_value(&ident, this);
1210            ptx.resolve(&expr)
1211        }
1212        let mut context = Context::default();
1213        context.add_function("with", with);
1214
1215        let program = Program::compile("[1,2].with(a, a + a)").unwrap();
1216        let value = program.execute(&context);
1217        assert_eq!(
1218            value,
1219            Ok(Value::List(Arc::new(vec![
1220                Value::Int(1),
1221                Value::Int(2),
1222                Value::Int(1),
1223                Value::Int(2)
1224            ])))
1225        );
1226    }
1227}