cel_cxx/variable/
registry.rs

1//! Variable registry for managing variable declarations.
2//!
3//! This module provides the [`VariableRegistry`] type for declaring variables
4//! and their types in CEL environments. The registry tracks variable names
5//! and their expected types for compile-time validation.
6//!
7//! # Features
8//!
9//! - **Type declarations**: Associate variable names with CEL types
10//! - **Validation**: Ensure variable bindings match declared types
11//! - **Lookup**: Efficient variable type resolution during compilation
12//! - **Iteration**: Enumerate all declared variables
13
14use crate::values::*;
15use crate::Error;
16use crate::ValueType;
17use std::collections::HashMap;
18
19/// Compile-time variable registry.
20///
21/// `VariableRegistry` manages variable declarations and constant definitions during the CEL environment
22/// compilation phase. It maintains a mapping from variable names to variable entries, where each entry
23/// can be either:
24///
25/// - A constant value ([`Constant`]): A fixed value known at compile time
26/// - A variable declaration: A type declaration with value provided at runtime
27///
28/// # Examples
29///
30/// ```rust,no_run
31/// use cel_cxx::{ValueType, VariableRegistry};
32///
33/// let mut registry = VariableRegistry::new();
34///
35/// // Define constants
36/// registry.define_constant("PI", 3.14159)?;
37/// registry.define_constant("APP_NAME", "MyApp")?;
38///
39/// // Declare variables
40/// registry.declare::<String>("user_input")?;
41///
42/// assert_eq!(registry.len(), 3);
43/// # Ok::<(), cel_cxx::Error>(())
44/// ```
45#[derive(Debug, Default)]
46pub struct VariableRegistry {
47    entries: HashMap<String, VariableDeclOrConstant>,
48}
49
50impl VariableRegistry {
51    /// Creates a new empty variable registry.
52    ///
53    /// # Returns
54    ///
55    /// A new empty `VariableRegistry`
56    pub fn new() -> Self {
57        Self {
58            entries: HashMap::new(),
59        }
60    }
61
62    /// Defines a constant value.
63    ///
64    /// Constants are values that are known at compile time and don't change during evaluation.
65    /// They can be used directly in CEL expressions without requiring runtime bindings.
66    ///
67    /// # Type Parameters
68    ///
69    /// - `T`: The constant type, must implement [`IntoConstant`]
70    ///
71    /// # Parameters
72    ///
73    /// - `name`: The constant name
74    /// - `value`: The constant value
75    ///
76    /// # Returns
77    ///
78    /// Returns `&mut Self` to support method chaining, or [`Error`] if an error occurs
79    ///
80    /// # Examples
81    ///
82    /// ```rust,no_run
83    /// use cel_cxx::VariableRegistry;
84    ///
85    /// let mut registry = VariableRegistry::new();
86    /// registry
87    ///     .define_constant("PI", 3.14159)?
88    ///     .define_constant("APP_NAME", "MyApp")?
89    ///     .define_constant("MAX_USERS", 1000i64)?;
90    /// # Ok::<(), cel_cxx::Error>(())
91    /// ```
92    ///
93    /// [`IntoConstant`]: crate::values::IntoConstant
94    pub fn define_constant<T>(
95        &mut self,
96        name: impl Into<String>,
97        value: T,
98    ) -> Result<&mut Self, Error>
99    where
100        T: IntoConstant,
101    {
102        self.entries
103            .insert(name.into(), VariableDeclOrConstant::new_constant(value));
104        Ok(self)
105    }
106
107    /// Declares a variable with a specific type.
108    ///
109    /// Variable declarations only specify the type, with actual values provided at runtime
110    /// through [`Activation`]. The type is determined by the generic parameter `T` which
111    /// must implement [`TypedValue`].
112    ///
113    /// # Type Parameters
114    ///
115    /// - `T`: The variable type, must implement [`TypedValue`]
116    ///
117    /// # Parameters
118    ///
119    /// - `name`: The variable name
120    ///
121    /// # Returns
122    ///
123    /// Returns `&mut Self` to support method chaining, or [`Error`] if an error occurs
124    ///
125    /// # Examples
126    ///
127    /// ```rust,no_run
128    /// use cel_cxx::VariableRegistry;
129    ///
130    /// let mut registry = VariableRegistry::new();
131    /// registry
132    ///     .declare::<String>("user_name")?
133    ///     .declare::<i64>("user_id")?
134    ///     .declare::<bool>("is_admin")?;
135    /// # Ok::<(), cel_cxx::Error>(())
136    /// ```
137    ///
138    /// [`Activation`]: crate::Activation
139    /// [`TypedValue`]: crate::TypedValue
140    pub fn declare<T>(&mut self, name: impl Into<String>) -> Result<&mut Self, Error>
141    where
142        T: TypedValue,
143    {
144        self.entries
145            .insert(name.into(), VariableDeclOrConstant::new(T::value_type()));
146        Ok(self)
147    }
148
149    /// Returns an iterator over all variable entries.
150    ///
151    /// The iterator yields `(name, entry)` pairs for all registered variables and constants.
152    ///
153    /// # Returns
154    ///
155    /// Iterator yielding `(&String, &VariableDeclOrConstant)` pairs
156    pub fn entries(&self) -> impl Iterator<Item = (&String, &VariableDeclOrConstant)> {
157        self.entries.iter()
158    }
159
160    /// Returns a mutable iterator over all variable entries.
161    ///
162    /// The iterator yields `(name, entry)` pairs and allows modifying the entries.
163    ///
164    /// # Returns
165    ///
166    /// Iterator yielding `(&String, &mut VariableDeclOrConstant)` pairs
167    pub fn entries_mut(&mut self) -> impl Iterator<Item = (&String, &mut VariableDeclOrConstant)> {
168        self.entries.iter_mut()
169    }
170
171    /// Finds a variable entry by name.
172    ///
173    /// # Parameters
174    ///
175    /// - `name`: The variable name to search for
176    ///
177    /// # Returns
178    ///
179    /// Returns `Some(&VariableDeclOrConstant)` if found, `None` otherwise
180    pub fn find(&self, name: &str) -> Option<&VariableDeclOrConstant> {
181        self.entries.get(name)
182    }
183
184    /// Finds a mutable variable entry by name.
185    ///
186    /// # Parameters
187    ///
188    /// - `name`: The variable name to search for
189    ///
190    /// # Returns
191    ///
192    /// Returns `Some(&mut VariableDeclOrConstant)` if found, `None` otherwise
193    pub fn find_mut(&mut self, name: &str) -> Option<&mut VariableDeclOrConstant> {
194        self.entries.get_mut(name)
195    }
196
197    /// Removes a variable entry by name.
198    ///
199    /// # Parameters
200    ///
201    /// - `name`: The variable name to remove
202    ///
203    /// # Returns
204    ///
205    /// Returns `Some(VariableDeclOrConstant)` if the entry was found and removed, `None` otherwise
206    pub fn remove(&mut self, name: &str) -> Option<VariableDeclOrConstant> {
207        self.entries.remove(name)
208    }
209
210    /// Clears all variable entries.
211    pub fn clear(&mut self) {
212        self.entries.clear();
213    }
214
215    /// Returns the number of variable entries.
216    ///
217    /// # Returns
218    ///
219    /// Number of registered variables and constants
220    pub fn len(&self) -> usize {
221        self.entries.len()
222    }
223
224    /// Returns whether the registry is empty.
225    ///
226    /// # Returns
227    ///
228    /// `true` if no variables or constants are registered, `false` otherwise
229    pub fn is_empty(&self) -> bool {
230        self.entries.is_empty()
231    }
232}
233
234/// Union type representing either a variable declaration or constant definition.
235///
236/// `VariableDeclOrConstant` can hold either:
237/// - A constant value ([`Constant`]) that is known at compile time
238/// - A variable declaration ([`ValueType`]) that specifies the type for runtime binding
239///
240/// This allows the registry to handle both compile-time constants and runtime variables
241/// in a unified way.
242///
243/// # Examples
244///
245/// ```rust,no_run
246/// use cel_cxx::variable::VariableDeclOrConstant;
247/// use cel_cxx::types::ValueType;
248///
249/// // Create from constant
250/// let constant_entry = VariableDeclOrConstant::new_constant(42i64);
251/// assert!(constant_entry.is_constant());
252///
253/// // Create from declaration
254/// let decl_entry = VariableDeclOrConstant::new(ValueType::String);
255/// assert!(!decl_entry.is_constant());
256/// ```
257///
258/// [`Constant`]: crate::values::Constant
259#[derive(Debug)]
260pub struct VariableDeclOrConstant {
261    r#type: ValueType,
262    constant: Option<Constant>,
263}
264
265impl VariableDeclOrConstant {
266    /// Creates a new constant entry.
267    ///
268    /// # Type Parameters
269    ///
270    /// - `T`: The constant type, must implement [`IntoConstant`]
271    ///
272    /// # Parameters
273    ///
274    /// - `value`: The constant value
275    ///
276    /// # Returns
277    ///
278    /// New `VariableDeclOrConstant` containing the constant value
279    ///
280    /// [`IntoConstant`]: crate::values::IntoConstant
281    pub fn new_constant<T>(value: T) -> Self
282    where
283        T: IntoConstant,
284    {
285        Self {
286            r#type: T::value_type(),
287            constant: Some(value.into_constant()),
288        }
289    }
290
291    /// Creates a new variable declaration entry.
292    ///
293    /// # Parameters
294    ///
295    /// - `r#type`: The variable type
296    ///
297    /// # Returns
298    ///
299    /// New `VariableDeclOrConstant` containing the type declaration
300    pub fn new(r#type: ValueType) -> Self {
301        Self {
302            r#type,
303            constant: None,
304        }
305    }
306
307    /// Returns whether this entry is a constant.
308    ///
309    /// # Returns
310    ///
311    /// `true` if this entry contains a constant value, `false` if it's a declaration
312    pub fn is_constant(&self) -> bool {
313        self.constant.is_some()
314    }
315
316    /// Gets the type of this entry.
317    ///
318    /// For constants, this is the type of the constant value.
319    /// For declarations, this is the declared variable type.
320    ///
321    /// # Returns
322    ///
323    /// Reference to the [`ValueType`] of this entry
324    pub fn decl(&self) -> &ValueType {
325        &self.r#type
326    }
327
328    /// Gets the constant value, if this entry is a constant.
329    ///
330    /// # Returns
331    ///
332    /// `Some(&Constant)` if this is a constant entry, `None` if it's a declaration
333    pub fn constant(&self) -> Option<&Constant> {
334        self.constant.as_ref()
335    }
336}