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}