Skip to main content

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    /// Declares a variable with an explicit type.
150    ///
151    /// Unlike [`declare`](Self::declare) which infers the type from a generic parameter,
152    /// this method takes a [`ValueType`] directly. This is useful for types that
153    /// cannot be expressed via the `TypedValue` trait, such as protobuf message types.
154    ///
155    /// # Parameters
156    ///
157    /// - `name`: The variable name
158    /// - `value_type`: The explicit type for this variable
159    ///
160    /// # Returns
161    ///
162    /// Returns `&mut Self` to support method chaining, or [`Error`] if an error occurs
163    pub fn declare_with_type(
164        &mut self,
165        name: impl Into<String>,
166        value_type: ValueType,
167    ) -> Result<&mut Self, Error> {
168        self.entries
169            .insert(name.into(), VariableDeclOrConstant::new(value_type));
170        Ok(self)
171    }
172
173    /// Returns an iterator over all variable entries.
174    ///
175    /// The iterator yields `(name, entry)` pairs for all registered variables and constants.
176    ///
177    /// # Returns
178    ///
179    /// Iterator yielding `(&String, &VariableDeclOrConstant)` pairs
180    pub fn entries(&self) -> impl Iterator<Item = (&String, &VariableDeclOrConstant)> {
181        self.entries.iter()
182    }
183
184    /// Returns a mutable iterator over all variable entries.
185    ///
186    /// The iterator yields `(name, entry)` pairs and allows modifying the entries.
187    ///
188    /// # Returns
189    ///
190    /// Iterator yielding `(&String, &mut VariableDeclOrConstant)` pairs
191    pub fn entries_mut(&mut self) -> impl Iterator<Item = (&String, &mut VariableDeclOrConstant)> {
192        self.entries.iter_mut()
193    }
194
195    /// Finds a variable entry by name.
196    ///
197    /// # Parameters
198    ///
199    /// - `name`: The variable name to search for
200    ///
201    /// # Returns
202    ///
203    /// Returns `Some(&VariableDeclOrConstant)` if found, `None` otherwise
204    pub fn find(&self, name: &str) -> Option<&VariableDeclOrConstant> {
205        self.entries.get(name)
206    }
207
208    /// Finds a mutable variable entry by name.
209    ///
210    /// # Parameters
211    ///
212    /// - `name`: The variable name to search for
213    ///
214    /// # Returns
215    ///
216    /// Returns `Some(&mut VariableDeclOrConstant)` if found, `None` otherwise
217    pub fn find_mut(&mut self, name: &str) -> Option<&mut VariableDeclOrConstant> {
218        self.entries.get_mut(name)
219    }
220
221    /// Removes a variable entry by name.
222    ///
223    /// # Parameters
224    ///
225    /// - `name`: The variable name to remove
226    ///
227    /// # Returns
228    ///
229    /// Returns `Some(VariableDeclOrConstant)` if the entry was found and removed, `None` otherwise
230    pub fn remove(&mut self, name: &str) -> Option<VariableDeclOrConstant> {
231        self.entries.remove(name)
232    }
233
234    /// Clears all variable entries.
235    pub fn clear(&mut self) {
236        self.entries.clear();
237    }
238
239    /// Returns the number of variable entries.
240    ///
241    /// # Returns
242    ///
243    /// Number of registered variables and constants
244    pub fn len(&self) -> usize {
245        self.entries.len()
246    }
247
248    /// Returns whether the registry is empty.
249    ///
250    /// # Returns
251    ///
252    /// `true` if no variables or constants are registered, `false` otherwise
253    pub fn is_empty(&self) -> bool {
254        self.entries.is_empty()
255    }
256}
257
258/// Union type representing either a variable declaration or constant definition.
259///
260/// `VariableDeclOrConstant` can hold either:
261/// - A constant value ([`Constant`]) that is known at compile time
262/// - A variable declaration ([`ValueType`]) that specifies the type for runtime binding
263///
264/// This allows the registry to handle both compile-time constants and runtime variables
265/// in a unified way.
266///
267/// # Examples
268///
269/// ```rust,no_run
270/// use cel_cxx::variable::VariableDeclOrConstant;
271/// use cel_cxx::types::ValueType;
272///
273/// // Create from constant
274/// let constant_entry = VariableDeclOrConstant::new_constant(42i64);
275/// assert!(constant_entry.is_constant());
276///
277/// // Create from declaration
278/// let decl_entry = VariableDeclOrConstant::new(ValueType::String);
279/// assert!(!decl_entry.is_constant());
280/// ```
281///
282/// [`Constant`]: crate::values::Constant
283#[derive(Debug)]
284pub struct VariableDeclOrConstant {
285    r#type: ValueType,
286    constant: Option<Constant>,
287}
288
289impl VariableDeclOrConstant {
290    /// Creates a new constant entry.
291    ///
292    /// # Type Parameters
293    ///
294    /// - `T`: The constant type, must implement [`IntoConstant`]
295    ///
296    /// # Parameters
297    ///
298    /// - `value`: The constant value
299    ///
300    /// # Returns
301    ///
302    /// New `VariableDeclOrConstant` containing the constant value
303    ///
304    /// [`IntoConstant`]: crate::values::IntoConstant
305    pub fn new_constant<T>(value: T) -> Self
306    where
307        T: IntoConstant,
308    {
309        Self {
310            r#type: T::value_type(),
311            constant: Some(value.into_constant()),
312        }
313    }
314
315    /// Creates a new variable declaration entry.
316    ///
317    /// # Parameters
318    ///
319    /// - `r#type`: The variable type
320    ///
321    /// # Returns
322    ///
323    /// New `VariableDeclOrConstant` containing the type declaration
324    pub fn new(r#type: ValueType) -> Self {
325        Self {
326            r#type,
327            constant: None,
328        }
329    }
330
331    /// Returns whether this entry is a constant.
332    ///
333    /// # Returns
334    ///
335    /// `true` if this entry contains a constant value, `false` if it's a declaration
336    pub fn is_constant(&self) -> bool {
337        self.constant.is_some()
338    }
339
340    /// Gets the type of this entry.
341    ///
342    /// For constants, this is the type of the constant value.
343    /// For declarations, this is the declared variable type.
344    ///
345    /// # Returns
346    ///
347    /// Reference to the [`ValueType`] of this entry
348    pub fn decl(&self) -> &ValueType {
349        &self.r#type
350    }
351
352    /// Gets the constant value, if this entry is a constant.
353    ///
354    /// # Returns
355    ///
356    /// `Some(&Constant)` if this is a constant entry, `None` if it's a declaration
357    pub fn constant(&self) -> Option<&Constant> {
358        self.constant.as_ref()
359    }
360}