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}