pub struct EnvBuilder<'f, Fm: FnMarker = (), Rm: RuntimeMarker = ()> { /* private fields */ }
Expand description
Builder for creating CEL environments.
The EnvBuilder
allows you to configure a CEL environment by registering
functions, declaring variables, and setting up runtime options before
building the final environment.
§Type Parameters
'f
: Lifetime of functions that will be registeredFm
: Function marker type indicating sync/async function supportRm
: Runtime marker type indicating the async runtime (if any)
§Examples
use cel_cxx::*;
let env = Env::builder()
.register_global_function("double", |x: i64| -> i64 { x * 2 })?
.declare_variable::<String>("message")?
.build()?;
Implementations§
Source§impl<'f, Fm: FnMarker, Rm: RuntimeMarker> EnvBuilder<'f, Fm, Rm>
impl<'f, Fm: FnMarker, Rm: RuntimeMarker> EnvBuilder<'f, Fm, Rm>
Source§impl<'f, Fm: FnMarker, Rm: RuntimeMarker> EnvBuilder<'f, Fm, Rm>
impl<'f, Fm: FnMarker, Rm: RuntimeMarker> EnvBuilder<'f, Fm, Rm>
Sourcepub fn with_container(self, container: impl Into<String>) -> Self
pub fn with_container(self, container: impl Into<String>) -> Self
Sets the CEL container for the environment, which acts as a namespace for unqualified names.
Default: Empty string (root scope)
The container influences how unqualified names (like function or variable names) are resolved during expression compilation. This affects the CEL runtime’s name resolution behavior for types, functions, and variables.
§CEL Syntax Impact
When a container is set, unqualified names in CEL expressions are automatically prefixed with the container namespace:
// With container "my.app", this expression:
MyMessage{field: 123}
// is equivalent to:
my.app.MyMessage{field: 123}
§Examples
use cel_cxx::*;
// Set container for protobuf message resolution
let env = Env::builder()
.with_container("com.example.proto")
.build()?;
// Now "UserMessage" resolves to "com.example.proto.UserMessage"
let program = env.compile("UserMessage{name: 'Alice', id: 123}")?;
Sourcepub fn with_standard(self, enable: bool) -> Self
pub fn with_standard(self, enable: bool) -> Self
Enables or disables the CEL standard library of functions and macros.
Default: Enabled (true
)
The standard library provides a rich set of common functions for types like string
,
list
, map
, as well as logical and arithmetic operators. Disabling it can reduce
the environment’s footprint if only custom functions are needed.
§CEL Syntax Impact
When enabled, provides access to all standard CEL operations:
- Arithmetic:
+
,-
,*
,/
,%
- Comparison:
==
,!=
,<
,<=
,>
,>=
- Logical:
&&
,||
,!
- String operations:
+
(concatenation),contains()
,startsWith()
,endsWith()
,size()
- List operations:
size()
,in
,[]
(indexing),+
(concatenation) - Map operations:
size()
,in
,[]
(key access),+
(merge) - Type conversions:
int()
,uint()
,double()
,string()
,bytes()
- Conditional:
? :
(ternary operator) - Macros:
has()
,all()
,exists()
,exists_one()
,map()
,filter()
§Examples
use cel_cxx::*;
// Standard library enabled (default)
let env = Env::builder()
.with_standard(true)
.build()?;
// Can use standard functions
let program = env.compile("'hello'.size() + ' world'.size() == 11")?;
let result = program.evaluate(&Activation::new())?;
assert_eq!(result, Value::Bool(true));
// Standard library disabled
let env_minimal = Env::builder()
.with_standard(false)
.build()?;
// Standard functions not available - would cause compilation error
// env_minimal.compile("'hello'.size()")?; // Error!
Sourcepub fn with_optional(self, enable: bool) -> Self
pub fn with_optional(self, enable: bool) -> Self
Enables or disables support for CEL’s optional types and related syntax.
Default: Disabled (false
)
This enables the optional
type and related features like optional field selection (.?
),
optional index/key access ([?_]
), and optional value construction ({?key: ...}
).
Required for some extensions like regex that return optional values.
§CEL Syntax Impact
When enabled, adds support for:
- Optional type:
optional<T>
for values that may or may not be present - Optional field selection:
msg.?field
returnsoptional<T>
instead of error - Optional indexing:
list[?index]
andmap[?key]
returnoptional<T>
- Optional map construction:
{?'key': value}
only includes entry if value is present - Optional methods:
.hasValue()
,.value()
,.orValue(default)
- Optional literals:
optional.of(value)
,optional.none()
§Examples
use cel_cxx::*;
let env = Env::builder()
.with_optional(true)
.build()?;
// Optional field selection
let program = env.compile("msg.?field.orValue('default')")?;
// Optional map construction
let program2 = env.compile("{'name': 'bob', ?'age': optional.of(25)}")?;
// Optional indexing
let program3 = env.compile("list[?5].hasValue()")?;
Sourcepub fn with_ext_bindings(self, enable: bool) -> Self
pub fn with_ext_bindings(self, enable: bool) -> Self
Enables or disables the Bindings extension.
Default: Disabled (false
)
This extension provides the cel.bind()
macro, which allows for temporary variable
bindings within a CEL expression to improve readability and performance by avoiding
repeated calculations.
§Available Functions
Function | Description | Example |
---|---|---|
cel.bind(var, init, result) | Bind variable to initialization expression | cel.bind(x, 5, x * x) |
§CEL Syntax Impact
When enabled, adds the cel.bind()
macro that creates local variable scopes:
- Variables are scoped to the result expression
- Supports nested bindings
- Enables performance optimization through value reuse
- Improves readability of complex expressions
§Examples
use cel_cxx::*;
let env = Env::builder()
.with_ext_bindings(true)
.build()?;
// Simple binding
let program = env.compile("cel.bind(x, 5, x * x)")?;
let result = program.evaluate(&Activation::new())?;
assert_eq!(result, Value::Int(25));
// Nested bindings for complex calculations
let program2 = env.compile(r#"
cel.bind(a, 'hello',
cel.bind(b, 'world',
a + ' ' + b + '!'))
"#)?;
Sourcepub fn with_ext_encoders(self, enable: bool) -> Self
pub fn with_ext_encoders(self, enable: bool) -> Self
Enables or disables the Encoders extension.
Default: Disabled (false
)
This extension provides functions for encoding and decoding between common data formats, such as Base64. All functions handle edge cases gracefully and maintain CEL’s safety guarantees.
§Available Functions
Function | Description | Example |
---|---|---|
base64.encode(bytes) | Encode bytes to Base64 string | base64.encode(b'hello') |
base64.decode(string) | Decode Base64 string to bytes | base64.decode('aGVsbG8=') |
§CEL Syntax Impact
When enabled, adds encoding/decoding functions in the base64
namespace:
- Supports both standard and raw (unpadded) Base64 encoding
- Automatically handles missing padding in decode operations
- Returns errors for invalid Base64 input
§Examples
use cel_cxx::*;
let env = Env::builder()
.with_ext_encoders(true)
.build()?;
// Encode bytes to Base64
let program = env.compile("base64.encode(b'hello')")?;
let result = program.evaluate(&Activation::new())?;
assert_eq!(result, Value::String("aGVsbG8=".into()));
// Decode Base64 to bytes
let program2 = env.compile("base64.decode('aGVsbG8=')")?;
let result2 = program2.evaluate(&Activation::new())?;
assert_eq!(result2, Value::Bytes(b"hello".to_vec()));
Sourcepub fn with_ext_lists(self, enable: bool) -> Self
pub fn with_ext_lists(self, enable: bool) -> Self
Enables or disables the Lists extension.
Default: Disabled (false
)
This extension provides additional functions for working with lists, such as slicing, flattening, sorting, and deduplication. All functions maintain CEL’s immutability guarantees and return new lists rather than modifying existing ones.
§Available Functions
Function | Description | Example |
---|---|---|
list.slice(start, end) | Extract sub-list | [1,2,3,4].slice(1,3) → [2,3] |
list.flatten() | Flatten nested lists | [[1,2],[3,4]].flatten() → [1,2,3,4] |
list.flatten(depth) | Flatten to specified depth | [1,[2,[3]]].flatten(1) → [1,2,[3]] |
list.distinct() | Remove duplicates | [1,2,2,3].distinct() → [1,2,3] |
list.reverse() | Reverse list order | [1,2,3].reverse() → [3,2,1] |
list.sort() | Sort comparable elements | [3,1,2].sort() → [1,2,3] |
list.sortBy(var, expr) | Sort by key expression | users.sortBy(u, u.age) |
lists.range(n) | Generate number sequence | lists.range(3) → [0,1,2] |
lists.range(start, end) | Generate range | lists.range(2,5) → [2,3,4] |
§CEL Syntax Impact
When enabled, adds advanced list manipulation capabilities:
- Zero-based indexing for all operations
- Type safety for sort operations (comparable types only)
- Efficient deduplication and flattening algorithms
- Lazy evaluation for range generation
§Examples
use cel_cxx::*;
let env = Env::builder()
.with_ext_lists(true)
.build()?;
// List slicing
let program = env.compile("[1, 2, 3, 4].slice(1, 3)")?;
let result = program.evaluate(&Activation::new())?;
assert_eq!(result, Value::List(vec![Value::Int(2), Value::Int(3)]));
// List sorting
let program2 = env.compile("[3, 1, 2].sort()")?;
let result2 = program2.evaluate(&Activation::new())?;
assert_eq!(result2, Value::List(vec![Value::Int(1), Value::Int(2), Value::Int(3)]));
// Generate ranges
let program3 = env.compile("lists.range(3)")?;
let result3 = program3.evaluate(&Activation::new())?;
assert_eq!(result3, Value::List(vec![Value::Int(0), Value::Int(1), Value::Int(2)]));
Sourcepub fn with_ext_math(self, enable: bool) -> Self
pub fn with_ext_math(self, enable: bool) -> Self
Enables or disables the Math extension.
Default: Disabled (false
)
This extension provides advanced mathematical functions beyond the standard operators, including min/max operations, rounding functions, absolute value, sign detection, bitwise operations, floating point helpers, and square root. All functions are deterministic and side-effect free.
Note: All macros use the ‘math’ namespace; however, at the time of macro expansion the namespace looks just like any other identifier. If you are currently using a variable named ‘math’, the macro will likely work just as intended; however, there is some chance for collision.
§Available Functions
§Min/Max Operations
Function | Description | Example |
---|---|---|
math.greatest(...) | Greatest value from arguments/list | math.greatest(1,2,3) → 3 |
math.least(...) | Least value from arguments/list | math.least([1,2,3]) → 1 |
§Absolute Value and Sign
Function | Description | Example |
---|---|---|
math.abs(number) | Absolute value | math.abs(-5) → 5 |
math.sign(number) | Sign (-1, 0, or 1) | math.sign(-5) → -1 |
§Rounding Functions
Function | Description | Example |
---|---|---|
math.ceil(number) | Round up | math.ceil(3.14) → 4.0 |
math.floor(number) | Round down | math.floor(3.14) → 3.0 |
math.round(number) | Round to nearest | math.round(3.14) → 3.0 |
math.trunc(number) | Truncate decimals | math.trunc(3.14) → 3.0 |
§Bitwise Operations
Function | Description | Example |
---|---|---|
math.bitAnd(a,b) | Bitwise AND | math.bitAnd(5,3) → 1 |
math.bitOr(a,b) | Bitwise OR | math.bitOr(5,3) → 7 |
math.bitXor(a,b) | Bitwise XOR | math.bitXor(5,3) → 6 |
math.bitNot(n) | Bitwise NOT | math.bitNot(5) → -6 |
math.bitShiftLeft(n,bits) | Left bit shift | math.bitShiftLeft(5,1) → 10 |
math.bitShiftRight(n,bits) | Right bit shift | math.bitShiftRight(5,1) → 2 |
§Floating Point Helpers
Function | Description | Example |
---|---|---|
math.isInf(number) | Check if infinite | math.isInf(1.0/0.0) → true |
math.isNaN(number) | Check if NaN | math.isNaN(0.0/0.0) → true |
math.isFinite(number) | Check if finite | math.isFinite(1.2) → true |
§Square Root
Function | Description | Example |
---|---|---|
math.sqrt(number) | Square root | math.sqrt(81) → 9.0 |
§CEL Syntax Impact
When enabled, adds mathematical functions in the math
namespace:
- Supports both integer and floating-point operations
- Bitwise operations work on integer types only
- Rounding functions return double type
- Min/max functions preserve input type
- Floating point helpers work with double type
- Square root always returns double type
§Examples
use cel_cxx::*;
let env = Env::builder()
.with_ext_math(true)
.build()?;
// Greatest/least operations (macros)
let program = env.compile("math.greatest(5, 2, 8, 1)")?;
let result = program.evaluate(&Activation::new())?;
assert_eq!(result, Value::Int(8));
let program2 = env.compile("math.least([-42.0, -21.5, -100.0])")?;
let result2 = program2.evaluate(&Activation::new())?;
assert_eq!(result2, Value::Double(-100.0));
// Absolute value
let program3 = env.compile("math.abs(-5)")?;
let result3 = program3.evaluate(&Activation::new())?;
assert_eq!(result3, Value::Int(5));
// Rounding functions
let program4 = env.compile("math.ceil(3.14)")?;
let result4 = program4.evaluate(&Activation::new())?;
assert_eq!(result4, Value::Double(4.0));
// Bitwise operations
let program5 = env.compile("math.bitAnd(5, 3)")?;
let result5 = program5.evaluate(&Activation::new())?;
assert_eq!(result5, Value::Int(1));
// Floating point helpers
let program6 = env.compile("math.isFinite(1.2)")?;
let result6 = program6.evaluate(&Activation::new())?;
assert_eq!(result6, Value::Bool(true));
// Square root
let program7 = env.compile("math.sqrt(81)")?;
let result7 = program7.evaluate(&Activation::new())?;
assert_eq!(result7, Value::Double(9.0));
Sourcepub fn with_ext_proto(self, enable: bool) -> Self
pub fn with_ext_proto(self, enable: bool) -> Self
Enables or disables the Protocol Buffers (Protobuf) extension.
Default: Disabled (false
)
This provides enhanced support for working with Protocol Buffer messages, particularly for accessing and testing proto2 extension fields. Requires proper setup of Protobuf descriptors in the environment.
§Available Functions
Function | Description | Example |
---|---|---|
proto.getExt(msg, ext) | Get extension field value | proto.getExt(msg, my.extension) |
proto.hasExt(msg, ext) | Test extension field presence | proto.hasExt(msg, my.extension) |
§CEL Syntax Impact
When enabled, adds proto2 extension support:
proto.getExt()
returns extension value or default if not setproto.hasExt()
returns boolean indicating if extension is explicitly set- Extension names must be fully qualified (e.g.,
com.example.my_extension
) - Uses safe-traversal semantics (no errors on missing fields)
- Only works with proto2 syntax messages that support extensions
§Examples
use cel_cxx::*;
let env = Env::builder()
.with_ext_proto(true)
.build()?;
// Access extension field
let program = env.compile("proto.getExt(my_message, com.example.priority_ext)")?;
// Test extension presence
let program2 = env.compile("proto.hasExt(my_message, com.example.priority_ext)")?;
// Conditional processing based on extensions
let program3 = env.compile(r#"
proto.hasExt(msg, com.example.metadata_ext) ?
proto.getExt(msg, com.example.metadata_ext).value :
"default"
"#)?;
Sourcepub fn with_ext_regex(self, enable: bool) -> Self
pub fn with_ext_regex(self, enable: bool) -> Self
Enables or disables the Regular Expression (Regex) extension.
Default: Disabled (false
)
This extension provides functions for pattern matching on strings using regular expressions, including pattern extraction, replacement, and text processing. Requires optional types to be enabled for proper operation.
§Available Functions
Function | Description | Example |
---|---|---|
regex.extract(text, pattern) | Extract first match (optional) | regex.extract('hello', 'h(.*)o') → optional('ell') |
regex.extractAll(text, pattern) | Extract all matches | regex.extractAll('a1 b2', '\\d+') → ['1', '2'] |
regex.replace(text, pattern, replacement) | Replace all matches | regex.replace('hello', 'l', 'x') → 'hexxo' |
regex.replace(text, pattern, replacement, count) | Replace up to count | regex.replace('hello', 'l', 'x', 1) → 'hexlo' |
§CEL Syntax Impact
When enabled, adds regex functions in the regex
namespace:
regex.extract()
returnsoptional<string>
(requires optional types)- Supports 0 or 1 capture groups only (error for multiple groups)
- Uses standard regex syntax with proper escaping
- Replacement supports capture group references (
\1
,\2
, etc.) - Count parameter in replace: 0=no replacement, negative=replace all
§Examples
use cel_cxx::*;
let env = Env::builder()
.with_ext_regex(true)
.with_optional(true) // Required for regex.extract
.build()?;
// Pattern extraction
let program = env.compile(r#"regex.extract('hello world', 'hello (.*)')"#)?;
// Extract all matches
let program2 = env.compile(r#"regex.extractAll('id:123, id:456', 'id:(\\d+)')"#)?;
// Pattern replacement with capture groups
let program3 = env.compile(r#"regex.replace('John Doe', '(\\w+) (\\w+)', r'\2, \1')"#)?;
Sourcepub fn with_ext_re(self, enable: bool) -> Self
pub fn with_ext_re(self, enable: bool) -> Self
Enables or disables the Regular Expression (RE) extension.
Default: Disabled (false
)
This extension provides C++ specific regular expression functions built on the RE2 library, offering additional pattern matching capabilities with different semantics than the standard regex extension. This is specific to the C++ CEL implementation.
§Available Functions
Function | Description | Example |
---|---|---|
re.extract(text, pattern, rewrite) | Extract and rewrite with pattern | re.extract('Hello World', r'(\\w+) (\\w+)', r'\\2, \\1') |
re.capture(text, pattern) | Capture first group | re.capture('john@example.com', r'([^@]+)@') |
re.captureN(text, pattern) | Capture all groups as map | re.captureN('2023-12-25', r'(\\d{4})-(\\d{2})-(\\d{2})') |
§CEL Syntax Impact
When enabled, adds RE2-based regex functions in the re
namespace:
re.extract()
performs extraction and rewriting in one operationre.capture()
returns string of first capture groupre.captureN()
returns map with numbered/named capture groups- Uses RE2 library for consistent performance and safety
- Supports named capture groups in
captureN()
§Examples
use cel_cxx::*;
let env = Env::builder()
.with_ext_re(true)
.build()?;
// Extract and rewrite
let program = env.compile(r#"re.extract('Hello World', r'(\w+) (\w+)', r'\2, \1')"#)?;
// Capture first group
let program2 = env.compile(r#"re.capture('john@example.com', r'([^@]+)@')"#)?;
// Capture all groups
let program3 = env.compile(r#"re.captureN('2023-12-25', r'(\d{4})-(\d{2})-(\d{2})')"#)?;
Sourcepub fn with_ext_sets(self, enable: bool) -> Self
pub fn with_ext_sets(self, enable: bool) -> Self
Enables or disables the Sets extension.
Default: Disabled (false
)
This extension provides functions for set-based operations on lists, such as containment
checking, equivalence testing, and intersection detection. Note that CEL does not have
a native set
type; these functions treat lists as sets.
§Available Functions
Function | Description | Example |
---|---|---|
sets.contains(list1, list2) | Check if list1 contains all elements of list2 | sets.contains([1,2,3], [2,3]) → true |
sets.equivalent(list1, list2) | Check if lists are set equivalent | sets.equivalent([1,2,3], [3,2,1]) → true |
sets.intersects(list1, list2) | Check if lists have common elements | sets.intersects([1,2], [2,3]) → true |
§CEL Syntax Impact
When enabled, adds set operations in the sets
namespace:
- Treats lists as sets (order and duplicates don’t matter for equivalence)
- Uses standard CEL equality for element comparison
- Supports type coercion (e.g.,
1
,1.0
,1u
are considered equal) - Empty list operations:
contains([], [])
→true
,intersects([], [])
→false
- Works with any comparable types
§Examples
use cel_cxx::*;
let env = Env::builder()
.with_ext_sets(true)
.build()?;
// Set containment
let program = env.compile("sets.contains([1, 2, 3, 4], [2, 3])")?;
let result = program.evaluate(&Activation::new())?;
assert_eq!(result, Value::Bool(true));
// Set equivalence
let program2 = env.compile("sets.equivalent([1, 2, 3], [3, 2, 1])")?;
let result2 = program2.evaluate(&Activation::new())?;
assert_eq!(result2, Value::Bool(true));
// Set intersection
let program3 = env.compile("sets.intersects([1, 2], [2, 3])")?;
let result3 = program3.evaluate(&Activation::new())?;
assert_eq!(result3, Value::Bool(true));
Sourcepub fn with_ext_strings(self, enable: bool) -> Self
pub fn with_ext_strings(self, enable: bool) -> Self
Enables or disables the Strings extension.
Default: Disabled (false
)
This extension provides additional functions for string manipulation, including character access, searching, extraction, case conversion, formatting, and advanced text processing operations that go beyond the basic string operations in the standard library.
§Available Functions
Function | Description | Example |
---|---|---|
string.charAt(index) | Get character at index | 'hello'.charAt(1) → 'e' |
string.indexOf(substring) | Find first occurrence | 'hello'.indexOf('l') → 2 |
string.indexOf(substring, start) | Find from start position | 'hello'.indexOf('l', 3) → 3 |
string.lastIndexOf(substring) | Find last occurrence | 'hello'.lastIndexOf('l') → 3 |
string.substring(start) | Extract from start to end | 'hello'.substring(1) → 'ello' |
string.substring(start, end) | Extract substring | 'hello'.substring(1, 4) → 'ell' |
strings.quote(string) | Quote string for CEL | strings.quote('hello') → '"hello"' |
string.trim() | Remove whitespace | ' hello '.trim() → 'hello' |
list.join(separator) | Join strings | ['a','b'].join(',') → 'a,b' |
string.split(separator) | Split string | 'a,b,c'.split(',') → ['a','b','c'] |
string.lowerAscii() | Convert to lowercase | 'HELLO'.lowerAscii() → 'hello' |
string.upperAscii() | Convert to uppercase | 'hello'.upperAscii() → 'HELLO' |
string.replace(old, new) | Replace all occurrences | 'hello'.replace('l','x') → 'hexxo' |
string.replace(old, new, count) | Replace up to count | 'hello'.replace('l','x',1) → 'hexlo' |
string.format(args) | Printf-style formatting | 'Hello %s'.format(['World']) → 'Hello World' |
string.reverse() | Reverse string | 'hello'.reverse() → 'olleh' |
§CEL Syntax Impact
When enabled, adds advanced string manipulation capabilities:
- Zero-based indexing for character access and substring operations
- Safe out-of-bounds handling (empty string for invalid indices)
- ASCII-only case conversion (Unicode characters unchanged)
- Printf-style format placeholders:
%s
,%d
,%f
,%.Nf
- Efficient string processing with immutable operations
§Examples
use cel_cxx::*;
let env = Env::builder()
.with_ext_strings(true)
.build()?;
// String searching and extraction
let program = env.compile("'hello world'.substring('hello world'.indexOf(' ') + 1)")?;
let result = program.evaluate(&Activation::new())?;
assert_eq!(result, Value::String("world".into()));
// String formatting
let program2 = env.compile("'Hello, %s!'.format(['Alice'])")?;
let result2 = program2.evaluate(&Activation::new())?;
assert_eq!(result2, Value::String("Hello, Alice!".into()));
// String processing pipeline
let program3 = env.compile("' HELLO WORLD '.trim().lowerAscii().replace(' ', '_')")?;
let result3 = program3.evaluate(&Activation::new())?;
assert_eq!(result3, Value::String("hello_world".into()));
Sourcepub fn with_ext_select_optimization(self, enable: bool) -> Self
pub fn with_ext_select_optimization(self, enable: bool) -> Self
Enables or disables the select optimization extension.
Default: Disabled (false
)
This is an optimization that can improve the performance of select
expressions
(field access) by transforming them at compile time. It does not introduce new
user-visible functions but can change the evaluation cost of field access operations.
§CEL Syntax Impact
When enabled, provides compile-time optimizations for:
- Message field access operations
- Map key access patterns
- Nested field selection chains
- No new syntax or functions are added
- Transparent performance improvements
§Examples
use cel_cxx::*;
let env = Env::builder()
.with_ext_select_optimization(true)
.build()?;
// Field access operations may be optimized
let program = env.compile("user.profile.settings.theme")?;
// Map access patterns may be optimized
let program2 = env.compile("config['database']['host']")?;
Sourcepub fn register_function<F, Ffm, Args>(
self,
name: impl Into<String>,
member: bool,
f: F,
) -> Result<EnvBuilder<'f, <Ffm as FnMarkerAggr<Fm>>::Output, Rm>, Error>
pub fn register_function<F, Ffm, Args>( self, name: impl Into<String>, member: bool, f: F, ) -> Result<EnvBuilder<'f, <Ffm as FnMarkerAggr<Fm>>::Output, Rm>, Error>
Registers a function (either global or member).
This method allows you to register custom functions that can be called from CEL expressions. The function can be either a global function or a member function of a type.
§Function Registration Process
When you register a function, the system:
- Extracts type information from the function signature
- Creates type-safe conversion wrappers
- Stores both the type signature and implementation
- Updates the function marker type to track sync/async status
§Zero-Annotation Benefits
Functions are registered without explicit type annotations:
- Argument types are automatically inferred
- Return types are automatically determined
- Error handling is automatically supported for
Result<T, E>
returns - Reference parameters like
&str
are handled safely
§Arguments
name
- The name of the function as it will appear in CEL expressionsmember
- Whether this is a member function (true
) or global function (false
)f
- The function implementation (function pointer, closure, etc.)
§Type Parameters
F
- The function implementation typeFfm
- The function marker type (sync/async) inferred from the functionArgs
- The argument tuple type (automatically inferred)
§Returns
A new EnvBuilder
with updated function marker type. If this is the first
async function registered, the marker changes from ()
to Async
.
§Member vs Global Functions
§Global Functions
Called as function_name(args...)
:
max(a, b) // max function with two arguments
calculate(x, y, z) // calculate function with three arguments
§Member Functions
Called as object.method(args...)
:
text.contains(substring) // contains method on string
list.size() // size method on list
§Function Signature Support
Supports various function signatures:
- Simple functions:
fn(T) -> U
- Functions with errors:
fn(T) -> Result<U, E>
- Reference parameters:
fn(&str, i64) -> String
- Multiple parameters: Up to 10 parameters supported
- Closures: Move closures that capture environment
§Errors
Returns Error
if:
- Function name conflicts with existing registration
- Function signature is invalid or unsupported
- Type inference fails
§Examples
§Basic Functions
use cel_cxx::*;
let builder = Env::builder()
.register_function("add", false, |a: i64, b: i64| a + b)?
.register_function("greet", false, |name: &str| format!("Hello, {}!", name))?;
§Member Functions
use cel_cxx::*;
let builder = Env::builder()
.register_function("contains", true, |text: &str, substr: &str| text.contains(substr))?
.register_function("length", true, |text: &str| text.len() as i64)?;
// Usage in expressions:
// text.contains("hello")
// text.length()
§Functions with Error Handling
use cel_cxx::*;
let builder = Env::builder()
.register_function("divide", false, |a: f64, b: f64| -> Result<f64, Error> {
if b == 0.0 {
Err(Error::invalid_argument("division by zero"))
} else {
Ok(a / b)
}
})?;
§Closures with Captured Data
use cel_cxx::*;
let multiplier = 5;
let threshold = 100.0;
let builder = Env::builder()
.register_function("scale", false, move |x: i64| x * multiplier)?
.register_function("check_limit", false, move |value: f64| value < threshold)?;
Sourcepub fn register_member_function<F, Ffm, Args>(
self,
name: impl Into<String>,
f: F,
) -> Result<EnvBuilder<'f, <Ffm as FnMarkerAggr<Fm>>::Output, Rm>, Error>
pub fn register_member_function<F, Ffm, Args>( self, name: impl Into<String>, f: F, ) -> Result<EnvBuilder<'f, <Ffm as FnMarkerAggr<Fm>>::Output, Rm>, Error>
Registers a member function.
This is a convenience method for registering member functions, equivalent to
calling register_function(name, true, f)
. Member functions are called using
dot notation in CEL expressions: object.method(args...)
.
§Arguments
name
- The method name as it will appear in CEL expressionsf
- The function implementation
§Member Function Semantics
Member functions in CEL follow these patterns:
- First parameter is the “receiver” (the object before the dot)
- Additional parameters become method arguments
- Called as
receiver.method(arg1, arg2, ...)
§Examples
§String Methods
use cel_cxx::*;
let builder = Env::builder()
.register_member_function("upper", |s: &str| s.to_uppercase())?
.register_member_function("contains", |s: &str, substr: &str| s.contains(substr))?
.register_member_function("repeat", |s: &str, n: i64| s.repeat(n as usize))?;
// Usage in expressions:
// "hello".upper() -> "HELLO"
// "hello world".contains("world") -> true
// "abc".repeat(3) -> "abcabcabc"
§Numeric Methods
use cel_cxx::*;
let builder = Env::builder()
.register_member_function("abs", |x: f64| x.abs())?
.register_member_function("pow", |x: f64, exp: f64| x.powf(exp))?;
// Usage in expressions:
// (-5.5).abs() -> 5.5
// (2.0).pow(3.0) -> 8.0
Sourcepub fn register_global_function<F, Ffm, Args>(
self,
name: impl Into<String>,
f: F,
) -> Result<EnvBuilder<'f, <Ffm as FnMarkerAggr<Fm>>::Output, Rm>, Error>
pub fn register_global_function<F, Ffm, Args>( self, name: impl Into<String>, f: F, ) -> Result<EnvBuilder<'f, <Ffm as FnMarkerAggr<Fm>>::Output, Rm>, Error>
Registers a global function.
This is a convenience method for registering global functions, equivalent to
calling register_function(name, false, f)
. Global functions are called directly
by name in CEL expressions: function_name(args...)
.
§Arguments
name
- The function name as it will appear in CEL expressionsf
- The function implementation
§Global Function Characteristics
Global functions:
- Are called directly by name without a receiver object
- Can have 0 to 10 parameters
- Support all CEL-compatible parameter and return types
- Can capture environment variables (for closures)
§Function Naming Guidelines
- Use clear, descriptive names:
calculate_tax
,format_date
- Follow CEL naming conventions (snake_case is recommended)
- Avoid conflicts with built-in CEL functions
- Consider namespacing for domain-specific functions:
math_sqrt
,string_trim
§Examples
§Mathematical Functions
use cel_cxx::*;
let builder = Env::builder()
.register_global_function("add", |a: i64, b: i64| a + b)?
.register_global_function("multiply", |a: f64, b: f64| a * b)?
.register_global_function("max", |a: i64, b: i64| if a > b { a } else { b })?;
// Usage in expressions:
// add(10, 20) -> 30
// multiply(2.5, 4.0) -> 10.0
// max(15, 8) -> 15
§String Processing Functions
use cel_cxx::*;
let builder = Env::builder()
.register_global_function("concat", |a: &str, b: &str| format!("{}{}", a, b))?
.register_global_function("trim_prefix", |s: &str, prefix: &str| {
s.strip_prefix(prefix).unwrap_or(s).to_string()
})?;
// Usage in expressions:
// concat("Hello, ", "World!") -> "Hello, World!"
// trim_prefix("prefixed_text", "prefixed_") -> "text"
§Business Logic Functions
use cel_cxx::*;
let builder = Env::builder()
.register_global_function("calculate_discount", |price: f64, rate: f64| {
price * (1.0 - rate.min(1.0).max(0.0))
})?
.register_global_function("is_valid_email", |email: &str| {
email.contains('@') && email.contains('.')
})?;
// Usage in expressions:
// calculate_discount(100.0, 0.15) -> 85.0
// is_valid_email("user@domain.com") -> true
§Functions with Complex Logic
use cel_cxx::*;
use std::collections::HashMap;
// Function that processes collections
let builder = Env::builder()
.register_global_function("sum_positive", |numbers: Vec<i64>| {
numbers.iter().filter(|&x| *x > 0).sum::<i64>()
})?;
// Usage in expressions:
// sum_positive([1, -2, 3, -4, 5]) -> 9
Sourcepub fn declare_function<D>(
self,
name: impl Into<String>,
member: bool,
) -> Result<Self, Error>where
D: FunctionDecl,
pub fn declare_function<D>(
self,
name: impl Into<String>,
member: bool,
) -> Result<Self, Error>where
D: FunctionDecl,
Declares a function signature without providing an implementation.
This is useful when you want to declare that a function exists for type checking purposes, but will provide the implementation later via activation bindings.
§Arguments
name
- The name of the functionmember
- Whether this is a member function (true
) or global function (false
)
§Type Parameters
D
- The function declaration type that specifies the signature
Sourcepub fn declare_member_function<D>(
self,
name: impl Into<String>,
) -> Result<Self, Error>where
D: FunctionDecl,
pub fn declare_member_function<D>(
self,
name: impl Into<String>,
) -> Result<Self, Error>where
D: FunctionDecl,
Sourcepub fn declare_global_function<D>(
self,
name: impl Into<String>,
) -> Result<Self, Error>where
D: FunctionDecl,
pub fn declare_global_function<D>(
self,
name: impl Into<String>,
) -> Result<Self, Error>where
D: FunctionDecl,
Sourcepub fn define_constant<T>(
self,
name: impl Into<String>,
value: T,
) -> Result<Self, Error>where
T: IntoConstant,
pub fn define_constant<T>(
self,
name: impl Into<String>,
value: T,
) -> Result<Self, Error>where
T: IntoConstant,
Sourcepub fn declare_variable<T>(self, name: impl Into<String>) -> Result<Self, Error>where
T: TypedValue,
pub fn declare_variable<T>(self, name: impl Into<String>) -> Result<Self, Error>where
T: TypedValue,
Declares a variable of a specific type.
This declares that a variable of the given name and type may be provided during evaluation. The actual value must be bound in the activation when evaluating expressions.
§Arguments
name
- The name of the variable
§Type Parameters
T
- The type of the variable
§Examples
use cel_cxx::*;
let builder = Env::builder()
.declare_variable::<String>("user_name")?
.declare_variable::<i64>("age")?;
Sourcepub fn build(self) -> Result<Env<'f, Fm, Rm>, Error>
pub fn build(self) -> Result<Env<'f, Fm, Rm>, Error>
Builds the environment from the configured builder.
This method consumes the builder and creates the final Env
instance
that can be used to compile CEL expressions.
§Returns
Returns a Result
containing the built Env
or an Error
if
the environment could not be created.
§Examples
use cel_cxx::*;
let env = Env::builder()
.declare_variable::<String>("name")?
.build()?;
§Errors
Returns an error if the environment configuration is invalid or if the underlying CEL environment cannot be created.
Source§impl<'f, Rm: RuntimeMarker> EnvBuilder<'f, (), Rm>
impl<'f, Rm: RuntimeMarker> EnvBuilder<'f, (), Rm>
Sourcepub fn force_async(self) -> EnvBuilder<'f, Async, Rm>
Available on crate feature async
only.
pub fn force_async(self) -> EnvBuilder<'f, Async, Rm>
async
only.Forces conversion to an async environment builder.
This method converts a synchronous environment builder to an asynchronous one, allowing it to register async functions and build async environments.
§Examples
use cel_cxx::*;
let async_builder = Env::builder().force_async();
Source§impl<'f, Fm: FnMarker> EnvBuilder<'f, Fm, ()>
impl<'f, Fm: FnMarker> EnvBuilder<'f, Fm, ()>
Sourcepub fn use_runtime<Rt: Runtime>(self) -> EnvBuilder<'f, Fm, Rt>
Available on crate feature async
only.
pub fn use_runtime<Rt: Runtime>(self) -> EnvBuilder<'f, Fm, Rt>
async
only.Sourcepub fn use_tokio(self) -> EnvBuilder<'f, Fm, Tokio>
Available on crate features async
and tokio
only.
pub fn use_tokio(self) -> EnvBuilder<'f, Fm, Tokio>
async
and tokio
only.Configures the builder to use the Tokio async runtime.
This is a convenience method for setting the runtime to Tokio.
Requires the tokio
feature to be enabled.
§Examples
use cel_cxx::*;
let builder = Env::builder().use_tokio();
Sourcepub fn use_async_std(self) -> EnvBuilder<'f, Fm, AsyncStd>
Available on crate features async
and async-std
only.
pub fn use_async_std(self) -> EnvBuilder<'f, Fm, AsyncStd>
async
and async-std
only.Configures the builder to use the async-std runtime.
This is a convenience method for setting the runtime to async-std.
Requires the async-std
feature to be enabled.
§Examples
use cel_cxx::*;
let builder = Env::builder().use_async_std();
Sourcepub fn use_smol(self) -> EnvBuilder<'f, Fm, Smol>
Available on crate features async
and smol
only.
pub fn use_smol(self) -> EnvBuilder<'f, Fm, Smol>
async
and smol
only.Configures the builder to use the smol runtime.
This is a convenience method for setting the runtime to smol.
Requires the smol
feature to be enabled.
§Examples
use cel_cxx::*;
let builder = Env::builder().use_smol();
Trait Implementations§
Source§impl<'f, Fm: FnMarker, Rm: RuntimeMarker> Debug for EnvBuilder<'f, Fm, Rm>
impl<'f, Fm: FnMarker, Rm: RuntimeMarker> Debug for EnvBuilder<'f, Fm, Rm>
Source§impl<'f, Fm: FnMarker, Rm: RuntimeMarker> Default for EnvBuilder<'f, Fm, Rm>
impl<'f, Fm: FnMarker, Rm: RuntimeMarker> Default for EnvBuilder<'f, Fm, Rm>
Auto Trait Implementations§
impl<'f, Fm, Rm> Freeze for EnvBuilder<'f, Fm, Rm>
impl<'f, Fm = (), Rm = ()> !RefUnwindSafe for EnvBuilder<'f, Fm, Rm>
impl<'f, Fm, Rm> Send for EnvBuilder<'f, Fm, Rm>
impl<'f, Fm, Rm> Sync for EnvBuilder<'f, Fm, Rm>
impl<'f, Fm, Rm> Unpin for EnvBuilder<'f, Fm, Rm>
impl<'f, Fm = (), Rm = ()> !UnwindSafe for EnvBuilder<'f, Fm, Rm>
Blanket Implementations§
Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
Source§impl<T> Instrument for T
impl<T> Instrument for T
Source§fn instrument(self, span: Span) -> Instrumented<Self>
fn instrument(self, span: Span) -> Instrumented<Self>
Source§fn in_current_span(self) -> Instrumented<Self>
fn in_current_span(self) -> Instrumented<Self>
Source§impl<T> IntoEither for T
impl<T> IntoEither for T
Source§fn into_either(self, into_left: bool) -> Either<Self, Self>
fn into_either(self, into_left: bool) -> Either<Self, Self>
self
into a Left
variant of Either<Self, Self>
if into_left
is true
.
Converts self
into a Right
variant of Either<Self, Self>
otherwise. Read moreSource§fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
self
into a Left
variant of Either<Self, Self>
if into_left(&self)
returns true
.
Converts self
into a Right
variant of Either<Self, Self>
otherwise. Read more