Module function

Source
Expand description

Function registration and implementation utilities.

The function system provides a flexible way to register and call functions in CEL expressions. Functions can be either compile-time declarations (type signatures only) or runtime implementations (callable code).

§Key Components

  • FunctionRegistry: Compile-time function registry for declaring function signatures and registering implementations
  • FunctionBindings: Runtime function bindings for calling functions during evaluation
  • FunctionOverloads: Function overload management supporting multiple implementations with different signatures
  • Declarations: Use FunctionDecl trait for compile-time type checking
  • Implementations: Use IntoFunction trait for runtime function calls

§Examples

use cel_cxx::*;

// Register a function implementation
let mut env = Env::builder()
    .register_global_function("greet", |name: String| -> String {
        format!("Hello, {}!", name)
    })?
    .build()?;

§Detailed Documentation

Zero-annotation function registration for CEL expression evaluation.

This module provides a type-safe, zero-annotation function registration system that allows Rust functions to be called from CEL expressions without manual type annotations or wrapper code.

§Two Function Systems

This module provides two distinct but complementary function systems:

§1. Function Registration (Runtime Implementation)

  • Purpose: Register actual callable Rust functions/closures
  • Entry point: IntoFunction trait and registration methods
  • Usage: env.register_function("name", function_impl)
  • Provides: Executable code that can be called during expression evaluation

§2. Function Declaration (Compile-Time Signatures)

  • Purpose: Declare function signatures for type checking without implementation
  • Entry point: FunctionDecl trait and declaration methods
  • Usage: env.declare_function::<SignatureType>("name")
  • Provides: Type information for compile-time validation and overload resolution

These systems work together: you can declare functions for type checking during development, then provide implementations later, or register complete functions that include both signature and implementation.

§Features

  • Zero-annotation registration: Functions can be registered without explicit type annotations
  • Lifetime-aware closures: Support for closures that capture environment variables
  • Reference return types: Safe handling of functions returning borrowed data like &str
  • Unified error handling: Automatic conversion of Result<T, E> return types
  • Async function support: Optional support for async functions (requires async feature)
  • Thread safety: All function implementations are Send + Sync

§How Zero-Annotation Works

The zero-annotation system is built on top of Rust’s type system and Generic Associated Types (GATs). When you register a function, the system automatically:

  1. Extracts argument types from the function signature using FunctionDecl
  2. Infers return types using the IntoResult trait
  3. Generates type-safe converters that handle lifetime erasure safely
  4. Creates a unified interface through the Function struct

§Type Conversion Process

For each argument type T, the system:

  • Uses T: FromValue + TypedValue to convert from CEL values
  • Leverages GATs (FromValue::Output<'a>) to handle borrowed data like &str
  • Safely handles lifetime relationships through internal conversion mechanisms

§Safety Guarantees

The lifetime handling is safe because:

  • Source CEL values remain valid for the entire function call
  • Converted arguments are immediately consumed by the target function
  • No references escape the function call scope

§Examples

§Basic function registration

use cel_cxx::{function::IntoFunction, Error};

// Simple function
fn add(a: i64, b: i64) -> i64 {
    a + b
}
let func = add.into_function();

// Function with error handling
fn divide(a: i64, b: i64) -> Result<i64, Error> {
    if b == 0 {
        Err(Error::invalid_argument("division by zero"))
    } else {
        Ok(a / b)
    }
}
let func = divide.into_function();

§Advanced: Reference return types

The system handles functions that return borrowed data:

use cel_cxx::function::*;
// Function returning borrowed data
fn get_first(items: Vec<&str>) -> &str {
    items.first().map_or("", |s| *s)
}
let func = get_first.into_function();

// The system automatically handles the lifetime relationships

§Closure registration

use cel_cxx::function::*;
// Capturing closure
let multiplier = 3;
let multiply = move |x: i64| -> i64 { x * multiplier };
let func = multiply.into_function();

// String processing closure
let prefix = String::from("Hello, ");
let with_prefix = move |name: &str| -> String {
    format!("{}{}", prefix, name)
};
let func = with_prefix.into_function();

§Function metadata and invocation

use cel_cxx::function::*;
fn add(a: i64, b: i64) -> i64 { a + b }
let func = add.into_function();

// Get function metadata
let arg_types = func.arguments(); // Vec<ValueType>
let return_type = func.result();  // ValueType

// Call the function (would need proper Value instances in real code)
// let args = vec![Value::from(10i64), Value::from(20i64)];
// let result = func.call(args);

§Async Functions

When the async feature is enabled, you can register async functions:

// Async function
async fn fetch_data(url: String) -> String {
    // Simulate async work
    tokio::time::sleep(tokio::time::Duration::from_millis(100)).await;
    format!("Data from {}", url)
}

let func = fetch_data.into_function();
// func.call() returns a Future that can be awaited

Re-exports§

pub use decl::*;
pub use overload::*;

Modules§

decl
Function declaration trait for CEL expression evaluation.
overload
Function overload management and resolution.

Structs§

Function
A type-erased function implementation that can be called from CEL expressions.
FunctionBindings
Runtime function bindings.
FunctionRegistry
Compile-time function registry.

Traits§

Arguments
Marker trait for function argument tuples.
IntoFunction
Trait for types that can be converted into function implementations.