cel_cxx/function/
registry.rs

1//! Function registry for managing registered functions.
2//!
3//! This module provides the [`FunctionRegistry`] type which serves as the
4//! central repository for all functions available in a CEL environment.
5//! It handles function registration, lookup, and overload management.
6//!
7//! # Features
8//!
9//! - **Function registration**: Add new function implementations
10//! - **Declaration support**: Register type signatures without implementations
11//! - **Overload management**: Handle multiple signatures for the same function name
12//! - **Efficient lookup**: Fast function resolution during expression evaluation
13//!
14//! # Thread Safety
15//!
16//! The registry is designed to be thread-safe and can be shared across
17//! multiple evaluation contexts.
18
19use super::*;
20use std::collections::HashMap;
21
22/// Compile-time function registry.
23///
24/// `FunctionRegistry` manages function declarations and implementations during the CEL environment
25/// compilation phase. It maintains a mapping from function names to function overloads, where each
26/// overload set can contain multiple function implementations with different signatures.
27///
28/// The registry supports two types of functions:
29///
30/// - **Function declarations**: Type signatures only for compile-time checking
31/// - **Function implementations**: Callable code for runtime execution
32///
33/// # Function Types
34///
35/// Functions can be registered as either:
36///
37/// - **Global functions**: Callable from any context
38/// - **Member functions**: Called as methods on values (e.g., `value.method()`)
39///
40/// # Lifetime Parameters
41///
42/// - `'f`: Lifetime of function implementations, allowing closures valid within specific scopes
43///
44/// # Examples
45///
46/// ```rust,no_run
47/// use cel_cxx::{FunctionRegistry, Error};
48///
49/// let mut registry = FunctionRegistry::new();
50///
51/// // Register function implementations
52/// fn add(a: i64, b: i64) -> Result<i64, Error> {
53///     Ok(a + b)
54/// }
55/// registry.register_global("add", add)?;
56///
57/// // Register member functions
58/// fn string_length(s: String) -> Result<i64, Error> {
59///     Ok(s.len() as i64)
60/// }
61/// registry.register_member("length", string_length)?;
62///
63/// // Register function declarations (type signatures only)
64/// registry.declare_global::<fn(String) -> Result<bool, Error>>("is_valid")?;
65///
66/// assert_eq!(registry.len(), 3);
67/// # Ok::<(), cel_cxx::Error>(())
68/// ```
69#[derive(Debug, Default)]
70pub struct FunctionRegistry<'f> {
71    entries: HashMap<String, FunctionOverloads<FunctionDeclOrImpl<'f>>>,
72}
73
74impl<'f> FunctionRegistry<'f> {
75    /// Creates a new empty function registry.
76    pub fn new() -> Self {
77        Self {
78            entries: HashMap::new(),
79        }
80    }
81}
82
83impl<'f> FunctionRegistry<'f> {
84    /// Registers a function implementation with zero-annotation type inference.
85    ///
86    /// Registers a callable function that can be invoked during CEL expression evaluation.
87    /// The function signature is automatically inferred from the Rust function type, eliminating
88    /// the need for manual type annotations.
89    ///
90    /// # Zero-Annotation Features
91    ///
92    /// - **Automatic type inference**: Function signature extracted from Rust function type
93    /// - **Lifetime handling**: Safe conversion of borrowed arguments like `&str`
94    /// - **Error conversion**: Automatic conversion of `Result<T, E>` return types
95    /// - **Async support**: Seamless handling of both sync and async functions
96    ///
97    /// # Type Parameters
98    ///
99    /// - `F`: Function type, must implement [`IntoFunction`]
100    /// - `Fm`: Function marker (sync or async), automatically inferred
101    /// - `Args`: Argument tuple type, automatically inferred from function signature
102    ///
103    /// # Parameters
104    ///
105    /// - `name`: Function name
106    /// - `member`: Whether this is a member function (true) or global function (false)
107    /// - `f`: Function implementation
108    ///
109    /// # Returns
110    ///
111    /// Returns `&mut Self` to support method chaining
112    ///
113    /// # Examples
114    ///
115    /// ## Basic functions with automatic type inference
116    ///
117    /// ```rust,no_run
118    /// use cel_cxx::FunctionRegistry;
119    ///
120    /// let mut registry = FunctionRegistry::new();
121    ///
122    /// // Zero-annotation function registration
123    /// registry.register("add", false, |a: i64, b: i64| a + b)?;
124    /// registry.register("greet", false, |name: &str| format!("Hello, {}!", name))?;
125    /// registry.register("is_empty", true, |s: String| s.is_empty())?;
126    /// # Ok::<(), cel_cxx::Error>(())
127    /// ```
128    ///
129    /// ## Error handling with automatic conversion
130    ///
131    /// ```rust,no_run
132    /// use cel_cxx::{FunctionRegistry, Error};
133    ///
134    /// let mut registry = FunctionRegistry::new();
135    ///
136    /// // Functions returning Result are automatically handled
137    /// registry.register("divide", false, |a: i64, b: i64| -> Result<i64, Error> {
138    ///     if b == 0 {
139    ///         Err(Error::invalid_argument("Division by zero"))
140    ///     } else {
141    ///         Ok(a / b)
142    ///     }
143    /// })?;
144    /// # Ok::<(), cel_cxx::Error>(())
145    /// ```
146    pub fn register<F, Fm, Args>(
147        &mut self,
148        name: impl Into<String>,
149        member: bool,
150        f: F,
151    ) -> Result<&mut Self, Error>
152    where
153        F: IntoFunction<'f, Fm, Args>,
154        Fm: FnMarker,
155        Args: Arguments,
156    {
157        let name = name.into();
158        let entry = self
159            .entries
160            .entry(name)
161            .or_insert_with(FunctionOverloads::new);
162        entry.add_impl(member, f.into_function())?;
163        Ok(self)
164    }
165
166    /// Registers a member function implementation.
167    ///
168    /// Convenience method for registering member functions that can be called as methods
169    /// on values (e.g., `"hello".length()`).
170    ///
171    /// # Examples
172    ///
173    /// ```rust,no_run
174    /// use cel_cxx::{FunctionRegistry, Error};
175    ///
176    /// let mut registry = FunctionRegistry::new();
177    ///
178    /// fn to_upper(s: String) -> Result<String, Error> {
179    ///     Ok(s.to_uppercase())
180    /// }
181    ///
182    /// registry.register_member("upper", to_upper)?;
183    /// # Ok::<(), cel_cxx::Error>(())
184    /// ```
185    pub fn register_member<F, Fm, Args>(
186        &mut self,
187        name: impl Into<String>,
188        f: F,
189    ) -> Result<&mut Self, Error>
190    where
191        F: IntoFunction<'f, Fm, Args>,
192        Fm: FnMarker,
193        Args: Arguments,
194    {
195        self.register(name, true, f)
196    }
197
198    /// Registers a global function implementation.
199    ///
200    /// Convenience method for registering global functions that can be called from any context.
201    ///
202    /// # Examples
203    ///
204    /// ```rust,no_run
205    /// use cel_cxx::{FunctionRegistry, Error};
206    ///
207    /// let mut registry = FunctionRegistry::new();
208    ///
209    /// fn max(a: i64, b: i64) -> Result<i64, Error> {
210    ///     Ok(a.max(b))
211    /// }
212    ///
213    /// registry.register_global("max", max)?;
214    /// # Ok::<(), cel_cxx::Error>(())
215    /// ```
216    pub fn register_global<F, Fm, Args>(
217        &mut self,
218        name: impl Into<String>,
219        f: F,
220    ) -> Result<&mut Self, Error>
221    where
222        F: IntoFunction<'f, Fm, Args>,
223        Fm: FnMarker,
224        Args: Arguments,
225    {
226        self.register(name, false, f)
227    }
228
229    /// Declares a function signature.
230    ///
231    /// Declares a function type signature for compile-time type checking without providing
232    /// an implementation. The function signature is determined by the generic parameter `D`
233    /// which must implement [`FunctionDecl`].
234    ///
235    /// # Type Parameters
236    ///
237    /// - `D`: Function declaration type, must implement [`FunctionDecl`]
238    ///
239    /// # Parameters
240    ///
241    /// - `name`: Function name
242    /// - `member`: Whether this is a member function (true) or global function (false)
243    ///
244    /// # Returns
245    ///
246    /// Returns `&mut Self` to support method chaining
247    ///
248    /// # Examples
249    ///
250    /// ```rust,no_run
251    /// use cel_cxx::{FunctionRegistry, Error};
252    ///
253    /// let mut registry = FunctionRegistry::new();
254    ///
255    /// // Declare global function signature
256    /// registry.declare::<fn(String) -> Result<bool, Error>>("validate", false)?;
257    ///
258    /// // Declare member function signature  
259    /// registry.declare::<fn(String) -> Result<i64, Error>>("size", true)?;
260    /// # Ok::<(), cel_cxx::Error>(())
261    /// ```
262    pub fn declare<D>(&mut self, name: impl Into<String>, member: bool) -> Result<&mut Self, Error>
263    where
264        D: FunctionDecl,
265    {
266        let name = name.into();
267        let entry = self
268            .entries
269            .entry(name)
270            .or_insert_with(FunctionOverloads::new);
271        entry.add_decl(member, D::function_type())?;
272        Ok(self)
273    }
274
275    /// Declares a member function signature.
276    ///
277    /// Convenience method for declaring member function signatures for compile-time
278    /// type checking without providing implementations.
279    ///
280    /// # Type Parameters
281    ///
282    /// - `D`: Function declaration type, must implement [`FunctionDecl`]
283    ///
284    /// # Parameters
285    ///
286    /// - `name`: Function name
287    ///
288    /// # Returns
289    ///
290    /// Returns `&mut Self` to support method chaining
291    ///
292    /// # Examples
293    ///
294    /// ```rust,no_run
295    /// use cel_cxx::{FunctionRegistry, Error};
296    ///
297    /// let mut registry = FunctionRegistry::new();
298    ///
299    /// // Declare member function signature
300    /// registry.declare_member::<fn(String) -> i64>("hash")?;
301    /// # Ok::<(), cel_cxx::Error>(())
302    /// ```
303    pub fn declare_member<D>(&mut self, name: impl Into<String>) -> Result<&mut Self, Error>
304    where
305        D: FunctionDecl,
306    {
307        self.declare::<D>(name, true)
308    }
309
310    /// Declares a global function signature.
311    ///
312    /// Convenience method for declaring global function signatures for compile-time
313    /// type checking without providing implementations.
314    ///
315    /// # Type Parameters
316    ///
317    /// - `D`: Function declaration type, must implement [`FunctionDecl`]
318    ///
319    /// # Parameters
320    ///
321    /// - `name`: Function name
322    ///
323    /// # Returns
324    ///
325    /// Returns `&mut Self` to support method chaining
326    ///
327    /// # Examples
328    ///
329    /// ```rust,no_run
330    /// use cel_cxx::{FunctionRegistry, Error};
331    ///
332    /// let mut registry = FunctionRegistry::new();
333    ///
334    /// // Declare global function signature
335    /// registry.declare_global::<fn(String, String) -> Result<String, Error>>("concat")?;
336    /// # Ok::<(), cel_cxx::Error>(())
337    /// ```
338    pub fn declare_global<D>(&mut self, name: impl Into<String>) -> Result<&mut Self, Error>
339    where
340        D: FunctionDecl,
341    {
342        self.declare::<D>(name, false)
343    }
344
345    /// Finds function overloads by name.
346    ///
347    /// # Parameters
348    ///
349    /// - `name`: Function name to search for
350    ///
351    /// # Returns
352    ///
353    /// `Some(&FunctionOverloads)` if found, `None` if not found
354    pub fn find(&self, name: &str) -> Option<&FunctionOverloads<FunctionDeclOrImpl<'f>>> {
355        self.entries.get(name)
356    }
357
358    /// Finds function overloads by name (mutable).
359    ///
360    /// # Parameters
361    ///
362    /// - `name`: Function name to search for
363    ///
364    /// # Returns
365    ///
366    /// `Some(&mut FunctionOverloads)` if found, `None` if not found
367    pub fn find_mut(
368        &mut self,
369        name: &str,
370    ) -> Option<&mut FunctionOverloads<FunctionDeclOrImpl<'f>>> {
371        self.entries.get_mut(name)
372    }
373
374    /// Returns an iterator over all function entries.
375    ///
376    /// # Returns
377    ///
378    /// Iterator yielding `(&str, &FunctionOverloads)` pairs
379    pub fn entries(
380        &self,
381    ) -> impl Iterator<Item = (&str, &FunctionOverloads<FunctionDeclOrImpl<'f>>)> {
382        self.entries.iter().map(|(k, v)| (k.as_str(), v))
383    }
384
385    /// Returns a mutable iterator over all function entries.
386    ///
387    /// # Returns
388    ///
389    /// Iterator yielding `(&str, &mut FunctionOverloads)` pairs
390    pub fn entries_mut(
391        &mut self,
392    ) -> impl Iterator<Item = (&str, &mut FunctionOverloads<FunctionDeclOrImpl<'f>>)> {
393        self.entries.iter_mut().map(|(k, v)| (k.as_str(), v))
394    }
395
396    /// Removes all overloads for a function name.
397    ///
398    /// # Parameters
399    ///
400    /// - `name`: Function name to remove
401    ///
402    /// # Returns
403    ///
404    /// `Ok(())` if removal was successful, `Err(Error)` if function not found
405    pub fn remove(&mut self, name: &str) -> Result<(), Error> {
406        self.entries
407            .remove(name)
408            .ok_or_else(|| Error::not_found(format!("Function '{name}' not found")))?;
409        Ok(())
410    }
411
412    /// Clears all registered functions.
413    pub fn clear(&mut self) {
414        self.entries.clear();
415    }
416
417    /// Returns the number of registered function names.
418    ///
419    /// Note: This counts function names, not individual overloads.
420    ///
421    /// # Returns
422    ///
423    /// Number of registered function names
424    pub fn len(&self) -> usize {
425        self.entries.len()
426    }
427
428    /// Returns whether the registry is empty.
429    ///
430    /// # Returns
431    ///
432    /// `true` if no functions are registered, `false` otherwise
433    pub fn is_empty(&self) -> bool {
434        self.entries.is_empty()
435    }
436}
437
438#[allow(dead_code)]
439#[allow(unused_variables)]
440#[allow(unused_imports)]
441#[cfg(test)]
442mod test {
443    use crate::{
444        types::{OpaqueType, ValueType},
445        values::OpaqueValue,
446        values::Optional,
447        values::{TypedOpaque, Value},
448        Error, Opaque,
449    };
450    use std::{
451        collections::{BTreeMap, HashMap},
452        sync::Arc,
453    };
454
455    use super::*;
456
457    fn f1(v: i64) -> Result<i64, Error> {
458        Ok(5)
459    }
460    fn f11(a1: i64, a2: i64) -> Result<i64, Error> {
461        Ok(5)
462    }
463
464    fn f2(a1: HashMap<i64, i64>) -> Result<i64, Error> {
465        Ok(5)
466    }
467    fn f3(a1: String) -> Result<i64, Error> {
468        Ok(5)
469    }
470    fn f4(a1: String, a2: String) -> Result<i64, Error> {
471        Ok(5)
472    }
473    fn f5(a1: String, a2: String, a3: HashMap<u64, Vec<Vec<i64>>>) -> Result<i64, Error> {
474        Ok(5)
475    }
476
477    #[cfg(feature = "derive")]
478    #[derive(Opaque, Debug, Clone, PartialEq)]
479    #[cel_cxx(type = "MyOpaque", crate = crate)]
480    #[cel_cxx(display)]
481    struct MyOpaque(pub i64);
482
483    #[cfg(feature = "derive")]
484    fn f6(a1: String, a2: MyOpaque, a3: HashMap<u64, Vec<Vec<i64>>>) -> Result<i64, Error> {
485        Ok(5)
486    }
487
488    fn f7(a1: &str) -> Result<(), Error> {
489        Ok(())
490    }
491
492    #[cfg(feature = "derive")]
493    fn f8(a1: &MyOpaque) -> &MyOpaque {
494        a1
495    }
496
497    #[cfg(feature = "derive")]
498    fn f9(a1: Optional<&MyOpaque>) -> Result<Option<&MyOpaque>, Error> {
499        Ok(a1.into_option())
500    }
501
502    async fn async_f1(a1: String, a2: i64, a3: Option<String>) -> Result<i64, Error> {
503        Ok(5)
504    }
505
506    fn f_map1(a1: HashMap<String, Vec<u8>>) -> Result<(), Error> {
507        Ok(())
508    }
509    fn f_map2(a1: HashMap<&str, &[u8]>) -> Result<(), Error> {
510        Ok(())
511    }
512    fn f_map3<'a>(a1: HashMap<&'a str, &'a str>) -> Result<BTreeMap<&'a str, &'a str>, Error> {
513        Ok(BTreeMap::from_iter(a1))
514    }
515
516    #[test]
517    fn test_register() -> Result<(), Error> {
518        let n = 100;
519        let lifetime_closure = |a: i64, b: i64| Ok::<_, Error>(a + b + n);
520        let mut registry = FunctionRegistry::new();
521        registry
522            .register_member("f1", f1)?
523            .register_member("f11", f11)?
524            .register_member("f2", f2)?
525            .register_member("f3", f3)?
526            .register_member("f4", f4)?
527            .register_member("f5", f5)?
528            .register_global("lifetime_closure", lifetime_closure)?
529            .register_global("f7", f7)?
530            .register_global("f_map1", f_map1)?
531            .register_global("f_map2", f_map2)?
532            .register_global("f_map3", f_map3)?;
533
534        #[cfg(feature = "derive")]
535        registry
536            .register_global("f6", f6)?
537            .register_global("f8", f8)?
538            .register_global("f9", f9)?;
539
540        #[cfg(feature = "async")]
541        #[cfg_attr(docsrs, doc(cfg(feature = "async")))]
542        let registry = registry.register_global("async_f1", async_f1)?;
543
544        //let variable = VariableDecl::builder()
545        //    .add::<i64, _>("v1")
546        //    .build(None);
547        //let env = Env::new(function, variable);
548
549        #[cfg(feature = "derive")]
550        {
551            let x = MyOpaque(1);
552            let y: Box<dyn Opaque> = Box::new(x);
553
554            let value: OpaqueValue = Box::new(MyOpaque(1));
555            assert!(value.is::<MyOpaque>());
556            assert!(value.downcast_ref::<MyOpaque>().is_some());
557            let value2 = value.clone().downcast::<MyOpaque>();
558            assert!(value2.is_ok());
559
560            let value3 = value.clone();
561            assert!(value3.is::<MyOpaque>());
562
563            let value4: OpaqueValue = Box::new(MyOpaque(1));
564            assert!(value4.is::<MyOpaque>());
565            assert!(value4.clone().downcast::<MyOpaque>().is_ok());
566            let value5 = value4.downcast::<MyOpaque>();
567            assert!(value5.is_ok());
568        }
569
570        Ok(())
571    }
572}