cel_cxx/variable/
bindings.rs

1//! Variable bindings for runtime value storage.
2//!
3//! This module provides the [`VariableBindings`] type for binding actual
4//! values to declared variables during CEL expression evaluation.
5//!
6//! # Features
7//!
8//! - **Value binding**: Associate variable names with runtime values
9//! - **Type checking**: Validate that bound values match declared types
10//! - **Efficient lookup**: Fast variable resolution during evaluation
11//! - **Lifetime management**: Proper handling of borrowed values
12
13use crate::function::*;
14use crate::marker::*;
15use crate::values::*;
16use crate::Error;
17use crate::ValueType;
18use std::collections::HashMap;
19
20/// Runtime variable bindings.
21///
22/// `VariableBindings` manages variable bindings during CEL expression evaluation.
23/// It maps variable names to concrete values or value providers.
24///
25/// Unlike compile-time [`VariableRegistry`], `VariableBindings` provides actual variable values
26/// at runtime and supports two types of bindings:
27///
28/// - **Value bindings**: Directly stored variable values
29/// - **Provider bindings**: Function-computed variable values through lazy evaluation
30///
31/// # Lifetime Parameters
32///
33/// - `'f`: Lifetime of function providers, allowing closures valid within specific scopes
34///
35/// # Examples
36///
37/// ```rust,no_run
38/// use cel_cxx::VariableBindings;
39///
40/// let mut bindings = VariableBindings::new();
41///
42/// // Bind static values
43/// bindings.bind("name", "Alice")?;
44/// bindings.bind("age", 30i64)?;
45///
46/// // Bind dynamic value providers
47/// bindings.bind_provider("current_time", || {
48///     std::time::SystemTime::now()
49/// })?;
50///
51/// assert_eq!(bindings.len(), 3);
52/// # Ok::<(), cel_cxx::Error>(())
53/// ```
54///
55/// [`VariableRegistry`]: crate::variable::VariableRegistry
56#[derive(Debug, Default)]
57pub struct VariableBindings<'f> {
58    entries: HashMap<String, VariableBinding<'f>>,
59}
60
61impl<'f> VariableBindings<'f> {
62    /// Creates a new empty variable bindings.
63    pub fn new() -> Self {
64        Self {
65            entries: HashMap::new(),
66        }
67    }
68}
69
70impl<'f> VariableBindings<'f> {
71    /// Binds a variable value.
72    ///
73    /// Binds a variable name to a concrete value. The value must implement [`IntoValue`] and [`TypedValue`] traits.
74    ///
75    /// # Type Parameters
76    ///
77    /// - `T`: Value type, must implement `IntoValue + TypedValue`
78    ///
79    /// # Parameters
80    ///
81    /// - `name`: Variable name
82    /// - `value`: Variable value
83    ///
84    /// # Returns
85    ///
86    /// Returns `&mut Self` to support method chaining
87    ///
88    /// # Examples
89    ///
90    /// ```rust,no_run
91    /// use cel_cxx::VariableBindings;
92    ///
93    /// let mut bindings = VariableBindings::new();
94    /// bindings
95    ///     .bind("user_id", 123i64)?
96    ///     .bind("is_admin", true)?
97    ///     .bind("username", "alice")?;
98    /// # Ok::<(), cel_cxx::Error>(())
99    /// ```
100    pub fn bind<T>(&mut self, name: impl Into<String>, value: T) -> Result<&mut Self, Error>
101    where
102        T: IntoValue + TypedValue,
103    {
104        self.entries
105            .insert(name.into(), VariableBinding::from_value(value));
106        Ok(self)
107    }
108
109    /// Binds a variable to a value provider.
110    ///
111    /// Binds a variable name to a provider function that computes the value dynamically.
112    /// This enables lazy evaluation and allows variables to have values computed at runtime.
113    ///
114    /// # Type Parameters
115    ///
116    /// - `F`: Provider function type, must implement `IntoFunction`
117    /// - `Fm`: Function marker type (sync/async)
118    ///
119    /// # Parameters
120    ///
121    /// - `name`: Variable name
122    /// - `provider`: Provider function that computes the variable value
123    ///
124    /// # Returns
125    ///
126    /// Returns `&mut Self` to support method chaining
127    ///
128    /// # Examples
129    ///
130    /// ```rust,no_run
131    /// use cel_cxx::VariableBindings;
132    ///
133    /// let mut bindings = VariableBindings::new();
134    /// bindings.bind_provider("current_time", || -> i64 {
135    ///     std::time::SystemTime::now()
136    ///         .duration_since(std::time::UNIX_EPOCH)
137    ///         .unwrap()
138    ///         .as_secs() as i64
139    /// })?;
140    /// # Ok::<(), cel_cxx::Error>(())
141    /// ```
142    pub fn bind_provider<F, Fm>(
143        &mut self,
144        name: impl Into<String>,
145        provider: F,
146    ) -> Result<&mut Self, Error>
147    where
148        F: IntoFunction<'f, Fm>,
149        Fm: FnMarker,
150    {
151        self.entries
152            .insert(name.into(), VariableBinding::from_provider(provider));
153        Ok(self)
154    }
155
156    /// Finds a variable binding by name.
157    ///
158    /// # Parameters
159    ///
160    /// - `name`: Variable name
161    ///
162    /// # Returns
163    ///
164    /// Returns `Some(&VariableBinding)` if found, `None` otherwise
165    pub fn find(&self, name: &str) -> Option<&VariableBinding<'f>> {
166        self.entries.get(name)
167    }
168
169    /// Finds a mutable variable binding by name.
170    ///
171    /// # Parameters
172    ///
173    /// - `name`: Variable name
174    ///
175    /// # Returns
176    ///
177    /// Returns `Some(&mut VariableBinding)` if found, `None` otherwise
178    pub fn find_mut(&mut self, name: &str) -> Option<&mut VariableBinding<'f>> {
179        self.entries.get_mut(name)
180    }
181
182    /// Returns an iterator over all variable bindings.
183    ///
184    /// The iterator yields `(name, binding)` pairs for all bound variables.
185    ///
186    /// # Returns
187    ///
188    /// Iterator yielding `(&str, &VariableBinding)` pairs
189    pub fn entries(&self) -> impl Iterator<Item = (&str, &VariableBinding<'f>)> {
190        self.entries
191            .iter()
192            .map(|(name, entry)| (name.as_str(), entry))
193    }
194
195    /// Returns a mutable iterator over all variable bindings.
196    ///
197    /// The iterator yields `(name, binding)` pairs and allows modifying the bindings.
198    ///
199    /// # Returns
200    ///
201    /// Iterator yielding `(&str, &mut VariableBinding)` pairs
202    pub fn entries_mut(&mut self) -> impl Iterator<Item = (&str, &mut VariableBinding<'f>)> {
203        self.entries
204            .iter_mut()
205            .map(|(name, entry)| (name.as_str(), entry))
206    }
207
208    /// Removes a variable binding by name.
209    ///
210    /// # Parameters
211    ///
212    /// - `name`: Variable name to remove
213    ///
214    /// # Returns
215    ///
216    /// Returns `Ok(())` if successfully removed, or an error if the variable doesn't exist
217    pub fn remove(&mut self, name: &str) -> Result<(), Error> {
218        if self.entries.remove(name).is_none() {
219            return Err(Error::not_found(format!("Variable {name} not found")));
220        }
221        Ok(())
222    }
223
224    /// Clears all variable bindings.
225    pub fn clear(&mut self) {
226        self.entries.clear();
227    }
228
229    /// Returns the number of variable bindings.
230    ///
231    /// # Returns
232    ///
233    /// Number of bound variables
234    pub fn len(&self) -> usize {
235        self.entries.len()
236    }
237
238    /// Returns whether the bindings are empty.
239    ///
240    /// # Returns
241    ///
242    /// `true` if no variables are bound, `false` otherwise
243    pub fn is_empty(&self) -> bool {
244        self.entries.is_empty()
245    }
246}
247
248/// Variable binding: value or provider.
249///
250/// `VariableBinding` represents a runtime variable binding, which can be:
251///
252/// - **Value binding** (`Value`): Directly stored variable value
253/// - **Provider binding** (`Provider`): Dynamically computed variable value through functions
254///
255/// # Lifetime Parameters
256///
257/// - `'f`: Lifetime of provider functions
258#[derive(Debug, Clone)]
259pub enum VariableBinding<'f> {
260    /// Directly stored value binding, containing (type, value) tuple
261    Value((ValueType, Value)),
262    /// Dynamic provider binding, computing values through functions
263    Provider(Function<'f>),
264}
265
266impl<'f> VariableBinding<'f> {
267    /// Creates a variable binding from a value.
268    ///
269    /// # Type Parameters
270    ///
271    /// - `T`: Value type, must implement `IntoValue + TypedValue`
272    ///
273    /// # Parameters
274    ///
275    /// - `value`: The value to bind
276    ///
277    /// # Returns
278    ///
279    /// New `VariableBinding::Value` containing the value and its type
280    pub fn from_value<T: IntoValue + TypedValue>(value: T) -> Self {
281        Self::Value((T::value_type(), value.into_value()))
282    }
283
284    /// Creates a variable binding from a provider function.
285    ///
286    /// # Type Parameters
287    ///
288    /// - `F`: Provider function type, must implement `IntoFunction`
289    /// - `Fm`: Function marker type (sync/async)
290    ///
291    /// # Parameters
292    ///
293    /// - `provider`: The provider function
294    ///
295    /// # Returns
296    ///
297    /// New `VariableBinding::Provider` containing the provider function
298    pub fn from_provider<F, Fm>(provider: F) -> Self
299    where
300        F: IntoFunction<'f, Fm>,
301        Fm: FnMarker,
302    {
303        Self::Provider(provider.into_function())
304    }
305
306    /// Returns the value type of this binding.
307    ///
308    /// For value bindings, returns the stored type. For provider bindings,
309    /// returns the return type of the provider function.
310    ///
311    /// # Returns
312    ///
313    /// The [`ValueType`] of this binding
314    pub fn value_type(&self) -> ValueType {
315        match self {
316            Self::Value((ty, _)) => ty.clone(),
317            Self::Provider(f) => f.function_type().result().clone(),
318        }
319    }
320
321    /// Returns whether this is a value binding.
322    ///
323    /// # Returns
324    ///
325    /// `true` if this is a `Value` binding, `false` if it's a `Provider` binding
326    pub fn is_value(&self) -> bool {
327        matches!(self, Self::Value(_))
328    }
329
330    /// Returns whether this is a provider binding.
331    ///
332    /// # Returns
333    ///
334    /// `true` if this is a `Provider` binding, `false` if it's a `Value` binding
335    pub fn is_provider(&self) -> bool {
336        matches!(self, Self::Provider(_))
337    }
338
339    /// Returns the value if this is a value binding.
340    ///
341    /// # Returns
342    ///
343    /// `Some(&Value)` if this is a value binding, `None` if it's a provider binding
344    pub fn as_value(&self) -> Option<&Value> {
345        match self {
346            Self::Value((_, value)) => Some(value),
347            Self::Provider(_) => None,
348        }
349    }
350
351    /// Returns the provider function if this is a provider binding.
352    ///
353    /// # Returns
354    ///
355    /// `Some(&Function)` if this is a provider binding, `None` if it's a value binding
356    pub fn as_provider(&self) -> Option<&Function<'f>> {
357        match self {
358            Self::Value(_) => None,
359            Self::Provider(f) => Some(f),
360        }
361    }
362
363    /// Converts this binding into a value if it's a value binding.
364    ///
365    /// # Returns
366    ///
367    /// `Some(Value)` if this is a value binding, `None` if it's a provider binding
368    pub fn into_value(self) -> Option<Value> {
369        match self {
370            Self::Value((_, value)) => Some(value),
371            Self::Provider(_) => None,
372        }
373    }
374
375    /// Converts this binding into a provider function if it's a provider binding.
376    ///
377    /// # Returns
378    ///
379    /// `Some(Function)` if this is a provider binding, `None` if it's a value binding
380    pub fn into_provider(self) -> Option<Function<'f>> {
381        match self {
382            Self::Value(_) => None,
383            Self::Provider(f) => Some(f),
384        }
385    }
386}