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#[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)]
41pub 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 pub fn get(&self, key: &Key) -> Option<&Value> {
56 self.map.get(key)
57
58 }
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 Bool(bool),
76 String(Arc<String>),
77}
78
79impl 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
110impl 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::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::Bool(v) => write!(f, "{v}"),
136 Key::String(v) => write!(f, "{v}"),
137 }
138 }
139}
140
141impl 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::String(v) => Ok(Key::String(v)),
151 Value::Bool(v) => Ok(Key::Bool(v)),
152 _ => Err(self),
153 }
154 }
155}
156
157impl<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)]
189pub enum Value {
191 List(Arc<Vec<Value>>),
192 Map(Map),
193
194 Function(Arc<String>, Option<Box<Value>>),
195
196 Int(i64),
198 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::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 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::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::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::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 (Value::Int(a), Value::Float(b)) => (*a as f64) == *b,
330 (Value::Float(a), Value::Int(b)) => *a == (*b as f64),
337 #[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::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 (Value::Int(a), Value::Float(b)) => (*a as f64).partial_cmp(b),
369 (Value::Float(a), Value::Int(b)) => a.partial_cmp(&(*b as f64)),
378 #[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::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::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
414impl<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
421impl From<Vec<u8>> for Value {
423 fn from(v: Vec<u8>) -> Self {
424 Value::Bytes(v.into())
425 }
426}
427
428impl 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
441impl<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
451impl<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::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(_), 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 fn member(self, name: &str) -> ResolveResult {
764 let name: Arc<String> = name.to_owned().into();
767
768 let child = match self {
771 Value::Map(ref m) => m.map.get(&name.clone().into()).cloned(),
772 _ => None,
773 };
774
775 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::Float(l), Value::Float(r)) => Value::Float(l + r).into(),
810
811 (Value::List(mut l), Value::List(mut r)) => {
812 {
813 let l = Arc::make_mut(&mut l);
816
817 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 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::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::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::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 (left, right) => Err(ExecutionError::UnsupportedBinaryOperator("rem", left, right)),
950 }
951 }
952}
953
954#[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#[cfg(feature = "time")]
976fn checked_op(op: TsOp, lhs: &DateTime, rhs: &crate::duration::Duration) -> ResolveResult {
977 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 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 < 1.1").unwrap();
1035 let value = program.execute(&context).unwrap();
1036 assert_eq!(value, true.into());
1037
1038 }
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]
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}