vortex_expr/
scope.rs

1// SPDX-License-Identifier: Apache-2.0
2// SPDX-FileCopyrightText: Copyright the Vortex contributors
3
4use std::any::TypeId;
5use std::ops::Deref;
6
7use vortex_array::arrays::StructArray;
8use vortex_array::{ArrayRef, IntoArray};
9
10use crate::scope_vars::{ScopeVar, ScopeVars};
11
12/// Scope define the evaluation context/scope that an expression uses when being evaluated.
13/// There is a special `Identifier` (`Identity`) which is used to bind the initial array being evaluated
14///
15/// Other identifier can be bound with variables either before execution or while executing (see `Let`).
16/// Values can be extracted from the scope using the `Var` expression.
17///
18/// ```code
19/// <let x = lit(1) in var(Identifier::Identity) + var(x), { Identity -> Primitive[1,2,3]> ->
20/// <var(Identifier::Identity) + var(x), { Identity -> Primitive[1,2,3], x -> ConstantArray(1)> ->
21/// <Primitive[1,2,3] + var(x), { Identity -> Primitive[1,2,3], x -> ConstantArray(1)> ->
22/// <Primitive[1,2,3] + ConstantArray(1), { Identity -> Primitive[1,2,3], x -> ConstantArray(1)> ->
23/// <Primitive[2,3,4], { Identity -> Primitive[1,2,3], x -> ConstantArray(1)>
24/// ```
25///
26/// Other values can be bound before execution e.g.
27///  `<var("x") + var("y") + var("z"), x -> ..., y -> ..., z -> ...>`
28#[derive(Clone)]
29pub struct Scope {
30    root: ArrayRef,
31    /// Variables that can be set on the scope during expression evaluation.
32    scope_vars: ScopeVars,
33}
34
35impl Scope {
36    /// Create a new scope with the given root array.
37    pub fn new(root: ArrayRef) -> Self {
38        Self {
39            root,
40            scope_vars: Default::default(),
41        }
42    }
43
44    /// Create a new scope with the root array set an empty struct.
45    pub fn empty(len: usize) -> Self {
46        Self::new(StructArray::new_with_len(len).into_array())
47    }
48
49    /// Return the root array of the scope.
50    pub fn root(&self) -> &ArrayRef {
51        &self.root
52    }
53
54    /// Returns a new evaluation scope with the given variable applied.
55    pub fn with_scope_var<V: ScopeVar>(mut self, var: V) -> Self {
56        self.scope_vars.insert(TypeId::of::<V>(), Box::new(var));
57        self
58    }
59
60    /// Returns the scope variable of type `V` if it exists.
61    pub fn scope_var<V: ScopeVar>(&self) -> Option<&V> {
62        self.scope_vars
63            .get(&TypeId::of::<V>())
64            .and_then(|boxed| (**boxed).as_any().downcast_ref::<V>())
65    }
66
67    /// Returns the mutable scope variable of type `V` if it exists.
68    pub fn scope_var_mut<V: ScopeVar>(&mut self) -> Option<&mut V> {
69        self.scope_vars
70            .get_mut(&TypeId::of::<V>())
71            .and_then(|boxed| (**boxed).as_any_mut().downcast_mut::<V>())
72    }
73}
74
75impl Deref for Scope {
76    type Target = ArrayRef;
77
78    fn deref(&self) -> &Self::Target {
79        &self.root
80    }
81}
82
83impl From<ArrayRef> for Scope {
84    fn from(value: ArrayRef) -> Self {
85        Self::new(value)
86    }
87}
88
89#[cfg(test)]
90mod test {
91    #[test]
92    fn test_scope_var() {
93        use super::*;
94
95        #[derive(Clone, PartialEq, Eq, Debug)]
96        struct TestVar {
97            value: i32,
98        }
99
100        let scope = Scope::empty(100);
101        assert!(scope.scope_var::<TestVar>().is_none());
102
103        let var = TestVar { value: 42 };
104        let mut scope = scope.with_scope_var(var.clone());
105        assert_eq!(scope.scope_var::<TestVar>(), Some(&var));
106
107        scope.scope_var_mut::<TestVar>().unwrap().value = 43;
108        assert_eq!(scope.scope_var::<TestVar>(), Some(&TestVar { value: 43 }));
109    }
110}