cel_core/eval/
activation.rs1use std::collections::HashMap;
8use std::sync::Arc;
9
10use super::Value;
11
12pub trait Activation: Send + Sync {
18 fn resolve(&self, name: &str) -> Option<Value>;
22
23 fn has(&self, name: &str) -> bool {
27 self.resolve(name).is_some()
28 }
29}
30
31#[derive(Debug, Clone, Default)]
33pub struct MapActivation {
34 bindings: HashMap<String, Value>,
35}
36
37impl MapActivation {
38 pub fn new() -> Self {
40 Self::default()
41 }
42
43 pub fn insert(&mut self, name: impl Into<String>, value: impl Into<Value>) {
45 self.bindings.insert(name.into(), value.into());
46 }
47
48 pub fn remove(&mut self, name: &str) -> Option<Value> {
50 self.bindings.remove(name)
51 }
52
53 pub fn len(&self) -> usize {
55 self.bindings.len()
56 }
57
58 pub fn is_empty(&self) -> bool {
60 self.bindings.is_empty()
61 }
62}
63
64impl Activation for MapActivation {
65 fn resolve(&self, name: &str) -> Option<Value> {
66 self.bindings.get(name).cloned()
67 }
68
69 fn has(&self, name: &str) -> bool {
70 self.bindings.contains_key(name)
71 }
72}
73
74impl FromIterator<(String, Value)> for MapActivation {
75 fn from_iter<T: IntoIterator<Item = (String, Value)>>(iter: T) -> Self {
76 Self {
77 bindings: iter.into_iter().collect(),
78 }
79 }
80}
81
82pub struct HierarchicalActivation<'a> {
87 parent: &'a dyn Activation,
88 local: HashMap<String, Value>,
89}
90
91impl<'a> HierarchicalActivation<'a> {
92 pub fn new(parent: &'a dyn Activation) -> Self {
94 Self {
95 parent,
96 local: HashMap::new(),
97 }
98 }
99
100 pub fn with_binding(mut self, name: impl Into<String>, value: impl Into<Value>) -> Self {
102 self.local.insert(name.into(), value.into());
103 self
104 }
105
106 pub fn insert(&mut self, name: impl Into<String>, value: impl Into<Value>) {
108 self.local.insert(name.into(), value.into());
109 }
110
111 pub fn remove(&mut self, name: &str) -> Option<Value> {
113 self.local.remove(name)
114 }
115}
116
117impl Activation for HierarchicalActivation<'_> {
118 fn resolve(&self, name: &str) -> Option<Value> {
119 self.local
121 .get(name)
122 .cloned()
123 .or_else(|| self.parent.resolve(name))
124 }
125
126 fn has(&self, name: &str) -> bool {
127 self.local.contains_key(name) || self.parent.has(name)
128 }
129}
130
131#[derive(Debug, Clone, Copy, Default)]
135pub struct EmptyActivation;
136
137impl EmptyActivation {
138 pub fn new() -> Self {
140 Self
141 }
142}
143
144impl Activation for EmptyActivation {
145 fn resolve(&self, _name: &str) -> Option<Value> {
146 None
147 }
148
149 fn has(&self, _name: &str) -> bool {
150 false
151 }
152}
153
154#[derive(Clone)]
156pub struct SharedActivation {
157 inner: Arc<dyn Activation>,
158}
159
160impl std::fmt::Debug for SharedActivation {
161 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
162 f.debug_struct("SharedActivation").finish_non_exhaustive()
163 }
164}
165
166impl SharedActivation {
167 pub fn new(activation: impl Activation + 'static) -> Self {
169 Self {
170 inner: Arc::new(activation),
171 }
172 }
173}
174
175impl Activation for SharedActivation {
176 fn resolve(&self, name: &str) -> Option<Value> {
177 self.inner.resolve(name)
178 }
179
180 fn has(&self, name: &str) -> bool {
181 self.inner.has(name)
182 }
183}
184
185impl<T: Activation> Activation for Arc<T> {
186 fn resolve(&self, name: &str) -> Option<Value> {
187 (**self).resolve(name)
188 }
189
190 fn has(&self, name: &str) -> bool {
191 (**self).has(name)
192 }
193}
194
195impl<T: Activation> Activation for Box<T> {
196 fn resolve(&self, name: &str) -> Option<Value> {
197 (**self).resolve(name)
198 }
199
200 fn has(&self, name: &str) -> bool {
201 (**self).has(name)
202 }
203}
204
205impl<T: Activation + ?Sized> Activation for &T {
206 fn resolve(&self, name: &str) -> Option<Value> {
207 (**self).resolve(name)
208 }
209
210 fn has(&self, name: &str) -> bool {
211 (**self).has(name)
212 }
213}
214
215#[cfg(test)]
216mod tests {
217 use super::*;
218
219 #[test]
220 fn test_map_activation() {
221 let mut activation = MapActivation::new();
222 activation.insert("x", 42i64);
223 activation.insert("name", "hello");
224
225 assert_eq!(activation.resolve("x"), Some(Value::Int(42)));
226 assert_eq!(activation.resolve("name"), Some(Value::from("hello")));
227 assert_eq!(activation.resolve("unknown"), None);
228
229 assert!(activation.has("x"));
230 assert!(!activation.has("unknown"));
231 }
232
233 #[test]
234 fn test_hierarchical_activation() {
235 let parent: MapActivation = [
236 ("x".to_string(), Value::Int(1)),
237 ("y".to_string(), Value::Int(2)),
238 ]
239 .into_iter()
240 .collect();
241
242 let child = HierarchicalActivation::new(&parent).with_binding("x", 10i64);
243
244 assert_eq!(child.resolve("x"), Some(Value::Int(10)));
246 assert_eq!(child.resolve("y"), Some(Value::Int(2)));
248 assert_eq!(child.resolve("z"), None);
250 }
251
252 #[test]
253 fn test_empty_activation() {
254 let activation = EmptyActivation::new();
255 assert_eq!(activation.resolve("anything"), None);
256 assert!(!activation.has("anything"));
257 }
258
259 #[test]
260 fn test_activation_insert_without_suffix() {
261 let mut activation = MapActivation::new();
263 activation.insert("count", 42); activation.insert("small", 5i8);
265 activation.insert("medium", 1000i16);
266 activation.insert("len", vec![1u8, 2, 3].len()); assert_eq!(activation.resolve("count"), Some(Value::Int(42)));
269 assert_eq!(activation.resolve("small"), Some(Value::Int(5)));
270 assert_eq!(activation.resolve("medium"), Some(Value::Int(1000)));
271 assert_eq!(activation.resolve("len"), Some(Value::UInt(3)));
272 }
273}