cel_cxx/env/mod.rs
1use crate::function::{Arguments, FunctionDecl, FunctionRegistry, IntoFunction};
2use crate::variable::VariableRegistry;
3use crate::{FnMarker, FnMarkerAggr, IntoConstant, RuntimeMarker};
4use std::sync::Arc;
5
6mod inner;
7
8use crate::ffi;
9use crate::{Error, Program, TypedValue};
10pub(crate) use inner::{EnvInner, EnvInnerOptions};
11
12#[cfg(feature = "async")]
13#[cfg_attr(docsrs, doc(cfg(feature = "async")))]
14use crate::marker::Async;
15
16/// CEL expression evaluation environment.
17///
18/// The `Env` struct represents a CEL environment that can compile expressions
19/// into programs. It encapsulates function registries, variable declarations,
20/// and type information needed for expression compilation.
21///
22/// # Type Parameters
23///
24/// - `'f`: Lifetime of functions registered in this environment
25/// - `Fm`: Function marker type indicating sync/async function support
26/// - `Rm`: Runtime marker type indicating the async runtime (if any)
27///
28/// # Examples
29///
30/// ## Basic Usage
31///
32/// ```rust,no_run
33/// use cel_cxx::*;
34///
35/// let env = Env::builder()
36/// .declare_variable::<String>("name")?
37/// .build()?;
38///
39/// let program = env.compile("'Hello, ' + name")?;
40/// # Ok::<(), cel_cxx::Error>(())
41/// ```
42///
43/// ## With Custom Functions
44///
45/// ```rust,no_run
46/// use cel_cxx::*;
47///
48/// let env = Env::builder()
49/// .register_global_function("add", |x: i64, y: i64| -> i64 { x + y })?
50/// .build()?;
51///
52/// let program = env.compile("add(10, 20)")?;
53/// # Ok::<(), cel_cxx::Error>(())
54/// ```
55pub struct Env<'f, Fm: FnMarker = (), Rm: RuntimeMarker = ()> {
56 pub(crate) inner: Arc<EnvInner<'f>>,
57 _fn_marker: std::marker::PhantomData<Fm>,
58 _rt_marker: std::marker::PhantomData<Rm>,
59}
60
61/// Type alias for asynchronous CEL environments.
62///
63/// This is a convenience type alias for environments that support asynchronous
64/// function evaluation.
65#[cfg(feature = "async")]
66#[cfg_attr(docsrs, doc(cfg(feature = "async")))]
67pub type AsyncEnv<'f, Rm = ()> = Env<'f, Async, Rm>;
68
69impl<'f> Env<'f> {
70 /// Creates a new environment builder.
71 ///
72 /// This is the starting point for creating a CEL environment. The builder
73 /// allows you to register functions, declare variables, and configure
74 /// the environment before building it.
75 ///
76 /// # Examples
77 ///
78 /// ```rust,no_run
79 /// use cel_cxx::*;
80 ///
81 /// let builder = Env::builder();
82 /// ```
83 pub fn builder() -> EnvBuilder<'f, ()> {
84 EnvBuilder::<(), ()>::new()
85 }
86}
87
88impl<'f, Fm: FnMarker, Rm: RuntimeMarker> Env<'f, Fm, Rm> {
89 /// Compiles a CEL expression into a Program.
90 ///
91 /// This method takes a CEL expression as a string or byte slice and compiles
92 /// it into a [`Program`] that can be evaluated with different activations.
93 ///
94 /// # Arguments
95 ///
96 /// * `source` - The CEL expression to compile
97 ///
98 /// # Returns
99 ///
100 /// Returns a [`Result`] containing the compiled [`Program`] or an [`Error`]
101 /// if compilation fails.
102 ///
103 /// # Examples
104 ///
105 /// ```rust,no_run
106 /// use cel_cxx::*;
107 ///
108 /// let env = Env::builder().build().unwrap();
109 /// let program = env.compile("1 + 2 * 3").unwrap();
110 /// ```
111 ///
112 /// # Errors
113 ///
114 /// Returns an error if:
115 /// - The expression contains syntax errors
116 /// - Referenced functions or variables are not declared
117 /// - Type checking fails
118 pub fn compile<S: AsRef<[u8]>>(&self, source: S) -> Result<Program<'f, Fm, Rm>, Error> {
119 self.inner.clone().compile::<Fm, Rm, _>(source)
120 }
121}
122
123/// Builder for creating CEL environments.
124///
125/// The `EnvBuilder` allows you to configure a CEL environment by registering
126/// functions, declaring variables, and setting up runtime options before
127/// building the final environment.
128///
129/// # Type Parameters
130///
131/// - `'f`: Lifetime of functions that will be registered
132/// - `Fm`: Function marker type indicating sync/async function support
133/// - `Rm`: Runtime marker type indicating the async runtime (if any)
134///
135/// # Examples
136///
137/// ```rust,no_run
138/// use cel_cxx::*;
139///
140/// let env = Env::builder()
141/// .register_global_function("double", |x: i64| -> i64 { x * 2 })?
142/// .declare_variable::<String>("message")?
143/// .build()?;
144/// # Ok::<(), cel_cxx::Error>(())
145/// ```
146pub struct EnvBuilder<'f, Fm: FnMarker = (), Rm: RuntimeMarker = ()> {
147 function_registry: FunctionRegistry<'f>,
148 variable_registry: VariableRegistry,
149 options: EnvInnerOptions,
150 _fn_marker: std::marker::PhantomData<Fm>,
151 _rt_marker: std::marker::PhantomData<Rm>,
152}
153
154impl<'f, Fm: FnMarker, Rm: RuntimeMarker> EnvBuilder<'f, Fm, Rm> {
155 /// Creates a new environment builder.
156 ///
157 /// # Examples
158 ///
159 /// ```rust,no_run
160 /// use cel_cxx::*;
161 ///
162 /// let builder = EnvBuilder::<()>::new();
163 /// ```
164 pub fn new() -> Self {
165 EnvBuilder {
166 function_registry: FunctionRegistry::new(),
167 variable_registry: VariableRegistry::new(),
168 options: EnvInnerOptions::default(),
169 _fn_marker: std::marker::PhantomData,
170 _rt_marker: std::marker::PhantomData,
171 }
172 }
173}
174
175impl<'f, Fm: FnMarker, Rm: RuntimeMarker> EnvBuilder<'f, Fm, Rm> {
176 /// Sets the CEL container for the environment, which acts as a namespace for unqualified names.
177 ///
178 /// **Default**: Empty string (root scope)
179 ///
180 /// The container influences how unqualified names (like function or variable names) are
181 /// resolved during expression compilation. This affects the CEL runtime's name resolution
182 /// behavior for types, functions, and variables.
183 ///
184 /// # CEL Syntax Impact
185 ///
186 /// When a container is set, unqualified names in CEL expressions are automatically prefixed
187 /// with the container namespace:
188 ///
189 /// ```cel
190 /// // With container "my.app", this expression:
191 /// MyMessage{field: 123}
192 /// // is equivalent to:
193 /// my.app.MyMessage{field: 123}
194 /// ```
195 ///
196 /// # Examples
197 ///
198 /// ```rust,no_run
199 /// use cel_cxx::*;
200 ///
201 /// // Set container for protobuf message resolution
202 /// let env = Env::builder()
203 /// .with_container("com.example.proto")
204 /// .build()?;
205 ///
206 /// // Now "UserMessage" resolves to "com.example.proto.UserMessage"
207 /// let program = env.compile("UserMessage{name: 'Alice', id: 123}")?;
208 /// # Ok::<(), cel_cxx::Error>(())
209 /// ```
210 pub fn with_container(mut self, container: impl Into<String>) -> Self {
211 self.options.container = container.into();
212 self
213 }
214
215 /// Enables or disables the CEL standard library of functions and macros.
216 ///
217 /// **Default**: Enabled (`true`)
218 ///
219 /// The standard library provides a rich set of common functions for types like `string`,
220 /// `list`, `map`, as well as logical and arithmetic operators. Disabling it can reduce
221 /// the environment's footprint if only custom functions are needed.
222 ///
223 /// # CEL Syntax Impact
224 ///
225 /// When enabled, provides access to all standard CEL operations:
226 /// - **Arithmetic**: `+`, `-`, `*`, `/`, `%`
227 /// - **Comparison**: `==`, `!=`, `<`, `<=`, `>`, `>=`
228 /// - **Logical**: `&&`, `||`, `!`
229 /// - **String operations**: `+` (concatenation), `contains()`, `startsWith()`, `endsWith()`, `size()`
230 /// - **List operations**: `size()`, `in`, `[]` (indexing), `+` (concatenation)
231 /// - **Map operations**: `size()`, `in`, `[]` (key access), `+` (merge)
232 /// - **Type conversions**: `int()`, `uint()`, `double()`, `string()`, `bytes()`
233 /// - **Conditional**: `? :` (ternary operator)
234 /// - **Macros**: `has()`, `all()`, `exists()`, `exists_one()`, `map()`, `filter()`
235 ///
236 /// # Examples
237 ///
238 /// ```rust
239 /// use cel_cxx::*;
240 ///
241 /// // Standard library enabled (default)
242 /// let env = Env::builder()
243 /// .with_standard(true)
244 /// .build()?;
245 ///
246 /// // Can use standard functions
247 /// let program = env.compile("'hello'.size() + ' world'.size() == 11")?;
248 /// let result = program.evaluate(&Activation::new())?;
249 /// assert_eq!(result, Value::Bool(true));
250 ///
251 /// // Standard library disabled
252 /// let env_minimal = Env::builder()
253 /// .with_standard(false)
254 /// .build()?;
255 ///
256 /// // Standard functions not available - would cause compilation error
257 /// // env_minimal.compile("'hello'.size()")?; // Error!
258 /// # Ok::<(), cel_cxx::Error>(())
259 /// ```
260 pub fn with_standard(mut self, enable: bool) -> Self {
261 self.options.enable_standard = enable;
262 self
263 }
264
265 /// Enables or disables support for CEL's optional types and related syntax.
266 ///
267 /// **Default**: Disabled (`false`)
268 ///
269 /// This enables the `optional` type and related features like optional field selection (`.?`),
270 /// optional index/key access (`[?_]`), and optional value construction (`{?key: ...}`).
271 /// Required for some extensions like regex that return optional values.
272 ///
273 /// # CEL Syntax Impact
274 ///
275 /// When enabled, adds support for:
276 /// - **Optional type**: `optional<T>` for values that may or may not be present
277 /// - **Optional field selection**: `msg.?field` returns `optional<T>` instead of error
278 /// - **Optional indexing**: `list[?index]` and `map[?key]` return `optional<T>`
279 /// - **Optional map construction**: `{?'key': value}` only includes entry if value is present
280 /// - **Optional methods**: `.hasValue()`, `.value()`, `.orValue(default)`
281 /// - **Optional literals**: `optional.of(value)`, `optional.none()`
282 ///
283 /// # Examples
284 ///
285 /// ```rust
286 /// use cel_cxx::*;
287 ///
288 /// let env = Env::builder()
289 /// .with_optional(true)
290 /// .build()?;
291 ///
292 /// // Optional field selection
293 /// let program = env.compile("msg.?field.orValue('default')")?;
294 ///
295 /// // Optional map construction
296 /// let program2 = env.compile("{'name': 'bob', ?'age': optional.of(25)}")?;
297 ///
298 /// // Optional indexing
299 /// let program3 = env.compile("list[?5].hasValue()")?;
300 /// # Ok::<(), cel_cxx::Error>(())
301 /// ```
302 pub fn with_optional(mut self, enable: bool) -> Self {
303 self.options.enable_optional = enable;
304 self
305 }
306
307 /// Enables or disables the Bindings extension.
308 ///
309 /// **Default**: Disabled (`false`)
310 ///
311 /// This extension provides the `cel.bind()` macro, which allows for temporary variable
312 /// bindings within a CEL expression to improve readability and performance by avoiding
313 /// repeated calculations.
314 ///
315 /// # Available Functions
316 ///
317 /// | Function | Description | Example |
318 /// |----------|-------------|---------|
319 /// | `cel.bind(var, init, result)` | Bind variable to initialization expression | `cel.bind(x, 5, x * x)` |
320 ///
321 /// # CEL Syntax Impact
322 ///
323 /// When enabled, adds the `cel.bind()` macro that creates local variable scopes:
324 /// - Variables are scoped to the result expression
325 /// - Supports nested bindings
326 /// - Enables performance optimization through value reuse
327 /// - Improves readability of complex expressions
328 ///
329 /// # Examples
330 ///
331 /// ```rust
332 /// use cel_cxx::*;
333 ///
334 /// let env = Env::builder()
335 /// .with_ext_bindings(true)
336 /// .build()?;
337 ///
338 /// // Simple binding
339 /// let program = env.compile("cel.bind(x, 5, x * x)")?;
340 /// let result = program.evaluate(&Activation::new())?;
341 /// assert_eq!(result, Value::Int(25));
342 ///
343 /// // Nested bindings for complex calculations
344 /// let program2 = env.compile(r#"
345 /// cel.bind(a, 'hello',
346 /// cel.bind(b, 'world',
347 /// a + ' ' + b + '!'))
348 /// "#)?;
349 /// # Ok::<(), cel_cxx::Error>(())
350 /// ```
351 pub fn with_ext_bindings(mut self, enable: bool) -> Self {
352 self.options.enable_ext_bindings = enable;
353 self
354 }
355
356 /// Enables or disables the Encoders extension.
357 ///
358 /// **Default**: Disabled (`false`)
359 ///
360 /// This extension provides functions for encoding and decoding between common data formats,
361 /// such as Base64. All functions handle edge cases gracefully and maintain CEL's safety guarantees.
362 ///
363 /// # Available Functions
364 ///
365 /// | Function | Description | Example |
366 /// |----------|-------------|---------|
367 /// | `base64.encode(bytes)` | Encode bytes to Base64 string | `base64.encode(b'hello')` |
368 /// | `base64.decode(string)` | Decode Base64 string to bytes | `base64.decode('aGVsbG8=')` |
369 ///
370 /// # CEL Syntax Impact
371 ///
372 /// When enabled, adds encoding/decoding functions in the `base64` namespace:
373 /// - Supports both standard and raw (unpadded) Base64 encoding
374 /// - Automatically handles missing padding in decode operations
375 /// - Returns errors for invalid Base64 input
376 ///
377 /// # Examples
378 ///
379 /// ```rust
380 /// use cel_cxx::*;
381 ///
382 /// let env = Env::builder()
383 /// .with_ext_encoders(true)
384 /// .build()?;
385 ///
386 /// // Encode bytes to Base64
387 /// let program = env.compile("base64.encode(b'hello')")?;
388 /// let result = program.evaluate(&Activation::new())?;
389 /// assert_eq!(result, Value::String("aGVsbG8=".into()));
390 ///
391 /// // Decode Base64 to bytes
392 /// let program2 = env.compile("base64.decode('aGVsbG8=')")?;
393 /// let result2 = program2.evaluate(&Activation::new())?;
394 /// assert_eq!(result2, Value::Bytes(b"hello".to_vec()));
395 /// # Ok::<(), cel_cxx::Error>(())
396 /// ```
397 pub fn with_ext_encoders(mut self, enable: bool) -> Self {
398 self.options.enable_ext_encoders = enable;
399 self
400 }
401
402 /// Enables or disables the Lists extension.
403 ///
404 /// **Default**: Disabled (`false`)
405 ///
406 /// This extension provides additional functions for working with lists, such as slicing,
407 /// flattening, sorting, and deduplication. All functions maintain CEL's immutability
408 /// guarantees and return new lists rather than modifying existing ones.
409 ///
410 /// # Available Functions
411 ///
412 /// | Function | Description | Example |
413 /// |----------|-------------|---------|
414 /// | `list.slice(start, end)` | Extract sub-list | `[1,2,3,4].slice(1,3)` → `[2,3]` |
415 /// | `list.flatten()` | Flatten nested lists | `[[1,2],[3,4]].flatten()` → `[1,2,3,4]` |
416 /// | `list.flatten(depth)` | Flatten to specified depth | `[1,[2,[3]]].flatten(1)` → `[1,2,[3]]` |
417 /// | `list.distinct()` | Remove duplicates | `[1,2,2,3].distinct()` → `[1,2,3]` |
418 /// | `list.reverse()` | Reverse list order | `[1,2,3].reverse()` → `[3,2,1]` |
419 /// | `list.sort()` | Sort comparable elements | `[3,1,2].sort()` → `[1,2,3]` |
420 /// | `list.sortBy(var, expr)` | Sort by key expression | `users.sortBy(u, u.age)` |
421 /// | `lists.range(n)` | Generate number sequence | `lists.range(3)` → `[0,1,2]` |
422 /// | `lists.range(start, end)` | Generate range | `lists.range(2,5)` → `[2,3,4]` |
423 ///
424 /// # CEL Syntax Impact
425 ///
426 /// When enabled, adds advanced list manipulation capabilities:
427 /// - Zero-based indexing for all operations
428 /// - Type safety for sort operations (comparable types only)
429 /// - Efficient deduplication and flattening algorithms
430 /// - Lazy evaluation for range generation
431 ///
432 /// # Examples
433 ///
434 /// ```rust
435 /// use cel_cxx::*;
436 ///
437 /// let env = Env::builder()
438 /// .with_ext_lists(true)
439 /// .build()?;
440 ///
441 /// // List slicing
442 /// let program = env.compile("[1, 2, 3, 4].slice(1, 3)")?;
443 /// let result = program.evaluate(&Activation::new())?;
444 /// assert_eq!(result, Value::List(vec![Value::Int(2), Value::Int(3)]));
445 ///
446 /// // List sorting
447 /// let program2 = env.compile("[3, 1, 2].sort()")?;
448 /// let result2 = program2.evaluate(&Activation::new())?;
449 /// assert_eq!(result2, Value::List(vec![Value::Int(1), Value::Int(2), Value::Int(3)]));
450 ///
451 /// // Generate ranges
452 /// let program3 = env.compile("lists.range(3)")?;
453 /// let result3 = program3.evaluate(&Activation::new())?;
454 /// assert_eq!(result3, Value::List(vec![Value::Int(0), Value::Int(1), Value::Int(2)]));
455 /// # Ok::<(), cel_cxx::Error>(())
456 /// ```
457 pub fn with_ext_lists(mut self, enable: bool) -> Self {
458 self.options.enable_ext_lists = enable;
459 self
460 }
461
462 /// Enables or disables the Math extension.
463 ///
464 /// **Default**: Disabled (`false`)
465 ///
466 /// This extension provides advanced mathematical functions beyond the standard operators,
467 /// including min/max operations, rounding functions, absolute value, sign detection,
468 /// bitwise operations, floating point helpers, and square root. All functions are
469 /// deterministic and side-effect free.
470 ///
471 /// **Note**: All macros use the 'math' namespace; however, at the time of macro
472 /// expansion the namespace looks just like any other identifier. If you are
473 /// currently using a variable named 'math', the macro will likely work just as
474 /// intended; however, there is some chance for collision.
475 ///
476 /// # Available Functions
477 ///
478 /// ## Min/Max Operations
479 /// | Function | Description | Example |
480 /// |----------|-------------|---------|
481 /// | `math.greatest(...)` | Greatest value from arguments/list | `math.greatest(1,2,3)` → `3` |
482 /// | `math.least(...)` | Least value from arguments/list | `math.least([1,2,3])` → `1` |
483 ///
484 /// ## Absolute Value and Sign
485 /// | Function | Description | Example |
486 /// |----------|-------------|---------|
487 /// | `math.abs(number)` | Absolute value | `math.abs(-5)` → `5` |
488 /// | `math.sign(number)` | Sign (-1, 0, or 1) | `math.sign(-5)` → `-1` |
489 ///
490 /// ## Rounding Functions
491 /// | Function | Description | Example |
492 /// |----------|-------------|---------|
493 /// | `math.ceil(number)` | Round up | `math.ceil(3.14)` → `4.0` |
494 /// | `math.floor(number)` | Round down | `math.floor(3.14)` → `3.0` |
495 /// | `math.round(number)` | Round to nearest | `math.round(3.14)` → `3.0` |
496 /// | `math.trunc(number)` | Truncate decimals | `math.trunc(3.14)` → `3.0` |
497 ///
498 /// ## Bitwise Operations
499 /// | Function | Description | Example |
500 /// |----------|-------------|---------|
501 /// | `math.bitAnd(a,b)` | Bitwise AND | `math.bitAnd(5,3)` → `1` |
502 /// | `math.bitOr(a,b)` | Bitwise OR | `math.bitOr(5,3)` → `7` |
503 /// | `math.bitXor(a,b)` | Bitwise XOR | `math.bitXor(5,3)` → `6` |
504 /// | `math.bitNot(n)` | Bitwise NOT | `math.bitNot(5)` → `-6` |
505 /// | `math.bitShiftLeft(n,bits)` | Left bit shift | `math.bitShiftLeft(5,1)` → `10` |
506 /// | `math.bitShiftRight(n,bits)` | Right bit shift | `math.bitShiftRight(5,1)` → `2` |
507 ///
508 /// ## Floating Point Helpers
509 /// | Function | Description | Example |
510 /// |----------|-------------|---------|
511 /// | `math.isInf(number)` | Check if infinite | `math.isInf(1.0/0.0)` → `true` |
512 /// | `math.isNaN(number)` | Check if NaN | `math.isNaN(0.0/0.0)` → `true` |
513 /// | `math.isFinite(number)` | Check if finite | `math.isFinite(1.2)` → `true` |
514 ///
515 /// ## Square Root
516 /// | Function | Description | Example |
517 /// |----------|-------------|---------|
518 /// | `math.sqrt(number)` | Square root | `math.sqrt(81)` → `9.0` |
519 ///
520 /// # CEL Syntax Impact
521 ///
522 /// When enabled, adds mathematical functions in the `math` namespace:
523 /// - Supports both integer and floating-point operations
524 /// - Bitwise operations work on integer types only
525 /// - Rounding functions return double type
526 /// - Min/max functions preserve input type
527 /// - Floating point helpers work with double type
528 /// - Square root always returns double type
529 ///
530 /// # Examples
531 ///
532 /// ```rust
533 /// use cel_cxx::*;
534 ///
535 /// let env = Env::builder()
536 /// .with_ext_math(true)
537 /// .build()?;
538 ///
539 /// // Greatest/least operations (macros)
540 /// let program = env.compile("math.greatest(5, 2, 8, 1)")?;
541 /// let result = program.evaluate(&Activation::new())?;
542 /// assert_eq!(result, Value::Int(8));
543 ///
544 /// let program2 = env.compile("math.least([-42.0, -21.5, -100.0])")?;
545 /// let result2 = program2.evaluate(&Activation::new())?;
546 /// assert_eq!(result2, Value::Double(-100.0));
547 ///
548 /// // Absolute value
549 /// let program3 = env.compile("math.abs(-5)")?;
550 /// let result3 = program3.evaluate(&Activation::new())?;
551 /// assert_eq!(result3, Value::Int(5));
552 ///
553 /// // Rounding functions
554 /// let program4 = env.compile("math.ceil(3.14)")?;
555 /// let result4 = program4.evaluate(&Activation::new())?;
556 /// assert_eq!(result4, Value::Double(4.0));
557 ///
558 /// // Bitwise operations
559 /// let program5 = env.compile("math.bitAnd(5, 3)")?;
560 /// let result5 = program5.evaluate(&Activation::new())?;
561 /// assert_eq!(result5, Value::Int(1));
562 ///
563 /// // Floating point helpers
564 /// let program6 = env.compile("math.isFinite(1.2)")?;
565 /// let result6 = program6.evaluate(&Activation::new())?;
566 /// assert_eq!(result6, Value::Bool(true));
567 ///
568 /// // Square root
569 /// let program7 = env.compile("math.sqrt(81)")?;
570 /// let result7 = program7.evaluate(&Activation::new())?;
571 /// assert_eq!(result7, Value::Double(9.0));
572 /// # Ok::<(), cel_cxx::Error>(())
573 /// ```
574 pub fn with_ext_math(mut self, enable: bool) -> Self {
575 self.options.enable_ext_math = enable;
576 self
577 }
578
579 /// Enables or disables the Protocol Buffers (Protobuf) extension.
580 ///
581 /// **Default**: Disabled (`false`)
582 ///
583 /// This provides enhanced support for working with Protocol Buffer messages, particularly
584 /// for accessing and testing proto2 extension fields. Requires proper setup of Protobuf
585 /// descriptors in the environment.
586 ///
587 /// # Available Functions
588 ///
589 /// | Function | Description | Example |
590 /// |----------|-------------|---------|
591 /// | `proto.getExt(msg, ext)` | Get extension field value | `proto.getExt(msg, my.extension)` |
592 /// | `proto.hasExt(msg, ext)` | Test extension field presence | `proto.hasExt(msg, my.extension)` |
593 ///
594 /// # CEL Syntax Impact
595 ///
596 /// When enabled, adds proto2 extension support:
597 /// - `proto.getExt()` returns extension value or default if not set
598 /// - `proto.hasExt()` returns boolean indicating if extension is explicitly set
599 /// - Extension names must be fully qualified (e.g., `com.example.my_extension`)
600 /// - Uses safe-traversal semantics (no errors on missing fields)
601 /// - Only works with proto2 syntax messages that support extensions
602 ///
603 /// # Examples
604 ///
605 /// ```rust,no_run
606 /// use cel_cxx::*;
607 ///
608 /// let env = Env::builder()
609 /// .with_ext_proto(true)
610 /// .build()?;
611 ///
612 /// // Access extension field
613 /// let program = env.compile("proto.getExt(my_message, com.example.priority_ext)")?;
614 ///
615 /// // Test extension presence
616 /// let program2 = env.compile("proto.hasExt(my_message, com.example.priority_ext)")?;
617 ///
618 /// // Conditional processing based on extensions
619 /// let program3 = env.compile(r#"
620 /// proto.hasExt(msg, com.example.metadata_ext) ?
621 /// proto.getExt(msg, com.example.metadata_ext).value :
622 /// "default"
623 /// "#)?;
624 /// # Ok::<(), cel_cxx::Error>(())
625 /// ```
626 pub fn with_ext_proto(mut self, enable: bool) -> Self {
627 self.options.enable_ext_proto = enable;
628 self
629 }
630
631 /// Enables or disables the Regular Expression (Regex) extension.
632 ///
633 /// **Default**: Disabled (`false`)
634 ///
635 /// This extension provides functions for pattern matching on strings using regular expressions,
636 /// including pattern extraction, replacement, and text processing. Requires optional types
637 /// to be enabled for proper operation.
638 ///
639 /// # Available Functions
640 ///
641 /// | Function | Description | Example |
642 /// |----------|-------------|---------|
643 /// | `regex.extract(text, pattern)` | Extract first match (optional) | `regex.extract('hello', 'h(.*)o')` → `optional('ell')` |
644 /// | `regex.extractAll(text, pattern)` | Extract all matches | `regex.extractAll('a1 b2', '\\d+')` → `['1', '2']` |
645 /// | `regex.replace(text, pattern, replacement)` | Replace all matches | `regex.replace('hello', 'l', 'x')` → `'hexxo'` |
646 /// | `regex.replace(text, pattern, replacement, count)` | Replace up to count | `regex.replace('hello', 'l', 'x', 1)` → `'hexlo'` |
647 ///
648 /// # CEL Syntax Impact
649 ///
650 /// When enabled, adds regex functions in the `regex` namespace:
651 /// - `regex.extract()` returns `optional<string>` (requires optional types)
652 /// - Supports 0 or 1 capture groups only (error for multiple groups)
653 /// - Uses standard regex syntax with proper escaping
654 /// - Replacement supports capture group references (`\1`, `\2`, etc.)
655 /// - Count parameter in replace: 0=no replacement, negative=replace all
656 ///
657 /// # Examples
658 ///
659 /// ```rust
660 /// use cel_cxx::*;
661 ///
662 /// let env = Env::builder()
663 /// .with_ext_regex(true)
664 /// .with_optional(true) // Required for regex.extract
665 /// .build()?;
666 ///
667 /// // Pattern extraction
668 /// let program = env.compile(r#"regex.extract('hello world', 'hello (.*)')"#)?;
669 ///
670 /// // Extract all matches
671 /// let program2 = env.compile(r#"regex.extractAll('id:123, id:456', 'id:(\\d+)')"#)?;
672 ///
673 /// // Pattern replacement with capture groups
674 /// let program3 = env.compile(r#"regex.replace('John Doe', '(\\w+) (\\w+)', r'\2, \1')"#)?;
675 /// # Ok::<(), cel_cxx::Error>(())
676 /// ```
677 pub fn with_ext_regex(mut self, enable: bool) -> Self {
678 self.options.enable_ext_regex = enable;
679 self
680 }
681
682 /// Enables or disables the Regular Expression (RE) extension.
683 ///
684 /// **Default**: Disabled (`false`)
685 ///
686 /// This extension provides C++ specific regular expression functions built on the RE2 library,
687 /// offering additional pattern matching capabilities with different semantics than the standard
688 /// regex extension. This is specific to the C++ CEL implementation.
689 ///
690 /// # Available Functions
691 ///
692 /// | Function | Description | Example |
693 /// |----------|-------------|---------|
694 /// | `re.extract(text, pattern, rewrite)` | Extract and rewrite with pattern | `re.extract('Hello World', r'(\\w+) (\\w+)', r'\\2, \\1')` |
695 /// | `re.capture(text, pattern)` | Capture first group | `re.capture('john@example.com', r'([^@]+)@')` |
696 /// | `re.captureN(text, pattern)` | Capture all groups as map | `re.captureN('2023-12-25', r'(\\d{4})-(\\d{2})-(\\d{2})')` |
697 ///
698 /// # CEL Syntax Impact
699 ///
700 /// When enabled, adds RE2-based regex functions in the `re` namespace:
701 /// - `re.extract()` performs extraction and rewriting in one operation
702 /// - `re.capture()` returns string of first capture group
703 /// - `re.captureN()` returns map with numbered/named capture groups
704 /// - Uses RE2 library for consistent performance and safety
705 /// - Supports named capture groups in `captureN()`
706 ///
707 /// # Examples
708 ///
709 /// ```rust
710 /// use cel_cxx::*;
711 ///
712 /// let env = Env::builder()
713 /// .with_ext_re(true)
714 /// .build()?;
715 ///
716 /// // Extract and rewrite
717 /// let program = env.compile(r#"re.extract('Hello World', r'(\w+) (\w+)', r'\2, \1')"#)?;
718 ///
719 /// // Capture first group
720 /// let program2 = env.compile(r#"re.capture('john@example.com', r'([^@]+)@')"#)?;
721 ///
722 /// // Capture all groups
723 /// let program3 = env.compile(r#"re.captureN('2023-12-25', r'(\d{4})-(\d{2})-(\d{2})')"#)?;
724 /// # Ok::<(), cel_cxx::Error>(())
725 /// ```
726 pub fn with_ext_re(mut self, enable: bool) -> Self {
727 self.options.enable_ext_re = enable;
728 self
729 }
730
731 /// Enables or disables the Sets extension.
732 ///
733 /// **Default**: Disabled (`false`)
734 ///
735 /// This extension provides functions for set-based operations on lists, such as containment
736 /// checking, equivalence testing, and intersection detection. Note that CEL does not have
737 /// a native `set` type; these functions treat lists as sets.
738 ///
739 /// # Available Functions
740 ///
741 /// | Function | Description | Example |
742 /// |----------|-------------|---------|
743 /// | `sets.contains(list1, list2)` | Check if list1 contains all elements of list2 | `sets.contains([1,2,3], [2,3])` → `true` |
744 /// | `sets.equivalent(list1, list2)` | Check if lists are set equivalent | `sets.equivalent([1,2,3], [3,2,1])` → `true` |
745 /// | `sets.intersects(list1, list2)` | Check if lists have common elements | `sets.intersects([1,2], [2,3])` → `true` |
746 ///
747 /// # CEL Syntax Impact
748 ///
749 /// When enabled, adds set operations in the `sets` namespace:
750 /// - Treats lists as sets (order and duplicates don't matter for equivalence)
751 /// - Uses standard CEL equality for element comparison
752 /// - Supports type coercion (e.g., `1`, `1.0`, `1u` are considered equal)
753 /// - Empty list operations: `contains([], [])` → `true`, `intersects([], [])` → `false`
754 /// - Works with any comparable types
755 ///
756 /// # Examples
757 ///
758 /// ```rust
759 /// use cel_cxx::*;
760 ///
761 /// let env = Env::builder()
762 /// .with_ext_sets(true)
763 /// .build()?;
764 ///
765 /// // Set containment
766 /// let program = env.compile("sets.contains([1, 2, 3, 4], [2, 3])")?;
767 /// let result = program.evaluate(&Activation::new())?;
768 /// assert_eq!(result, Value::Bool(true));
769 ///
770 /// // Set equivalence
771 /// let program2 = env.compile("sets.equivalent([1, 2, 3], [3, 2, 1])")?;
772 /// let result2 = program2.evaluate(&Activation::new())?;
773 /// assert_eq!(result2, Value::Bool(true));
774 ///
775 /// // Set intersection
776 /// let program3 = env.compile("sets.intersects([1, 2], [2, 3])")?;
777 /// let result3 = program3.evaluate(&Activation::new())?;
778 /// assert_eq!(result3, Value::Bool(true));
779 /// # Ok::<(), cel_cxx::Error>(())
780 /// ```
781 pub fn with_ext_sets(mut self, enable: bool) -> Self {
782 self.options.enable_ext_sets = enable;
783 self
784 }
785
786 /// Enables or disables the Strings extension.
787 ///
788 /// **Default**: Disabled (`false`)
789 ///
790 /// This extension provides additional functions for string manipulation, including character
791 /// access, searching, extraction, case conversion, formatting, and advanced text processing
792 /// operations that go beyond the basic string operations in the standard library.
793 ///
794 /// # Available Functions
795 ///
796 /// | Function | Description | Example |
797 /// |----------|-------------|---------|
798 /// | `string.charAt(index)` | Get character at index | `'hello'.charAt(1)` → `'e'` |
799 /// | `string.indexOf(substring)` | Find first occurrence | `'hello'.indexOf('l')` → `2` |
800 /// | `string.indexOf(substring, start)` | Find from start position | `'hello'.indexOf('l', 3)` → `3` |
801 /// | `string.lastIndexOf(substring)` | Find last occurrence | `'hello'.lastIndexOf('l')` → `3` |
802 /// | `string.substring(start)` | Extract from start to end | `'hello'.substring(1)` → `'ello'` |
803 /// | `string.substring(start, end)` | Extract substring | `'hello'.substring(1, 4)` → `'ell'` |
804 /// | `strings.quote(string)` | Quote string for CEL | `strings.quote('hello')` → `'"hello"'` |
805 /// | `string.trim()` | Remove whitespace | `' hello '.trim()` → `'hello'` |
806 /// | `list.join(separator)` | Join strings | `['a','b'].join(',')` → `'a,b'` |
807 /// | `string.split(separator)` | Split string | `'a,b,c'.split(',')` → `['a','b','c']` |
808 /// | `string.lowerAscii()` | Convert to lowercase | `'HELLO'.lowerAscii()` → `'hello'` |
809 /// | `string.upperAscii()` | Convert to uppercase | `'hello'.upperAscii()` → `'HELLO'` |
810 /// | `string.replace(old, new)` | Replace all occurrences | `'hello'.replace('l','x')` → `'hexxo'` |
811 /// | `string.replace(old, new, count)` | Replace up to count | `'hello'.replace('l','x',1)` → `'hexlo'` |
812 /// | `string.format(args)` | Printf-style formatting | `'Hello %s'.format(['World'])` → `'Hello World'` |
813 /// | `string.reverse()` | Reverse string | `'hello'.reverse()` → `'olleh'` |
814 ///
815 /// # CEL Syntax Impact
816 ///
817 /// When enabled, adds advanced string manipulation capabilities:
818 /// - Zero-based indexing for character access and substring operations
819 /// - Safe out-of-bounds handling (empty string for invalid indices)
820 /// - ASCII-only case conversion (Unicode characters unchanged)
821 /// - Printf-style format placeholders: `%s`, `%d`, `%f`, `%.Nf`
822 /// - Efficient string processing with immutable operations
823 ///
824 /// # Examples
825 ///
826 /// ```rust
827 /// use cel_cxx::*;
828 ///
829 /// let env = Env::builder()
830 /// .with_ext_strings(true)
831 /// .build()?;
832 ///
833 /// // String searching and extraction
834 /// let program = env.compile("'hello world'.substring('hello world'.indexOf(' ') + 1)")?;
835 /// let result = program.evaluate(&Activation::new())?;
836 /// assert_eq!(result, Value::String("world".into()));
837 ///
838 /// // String formatting
839 /// let program2 = env.compile("'Hello, %s!'.format(['Alice'])")?;
840 /// let result2 = program2.evaluate(&Activation::new())?;
841 /// assert_eq!(result2, Value::String("Hello, Alice!".into()));
842 ///
843 /// // String processing pipeline
844 /// let program3 = env.compile("' HELLO WORLD '.trim().lowerAscii().replace(' ', '_')")?;
845 /// let result3 = program3.evaluate(&Activation::new())?;
846 /// assert_eq!(result3, Value::String("hello_world".into()));
847 /// # Ok::<(), cel_cxx::Error>(())
848 /// ```
849 pub fn with_ext_strings(mut self, enable: bool) -> Self {
850 self.options.enable_ext_strings = enable;
851 self
852 }
853
854 /// Enables or disables the select optimization extension.
855 ///
856 /// **Default**: Disabled (`false`)
857 ///
858 /// This is an optimization that can improve the performance of `select` expressions
859 /// (field access) by transforming them at compile time. It does not introduce new
860 /// user-visible functions but can change the evaluation cost of field access operations.
861 ///
862 /// # CEL Syntax Impact
863 ///
864 /// When enabled, provides compile-time optimizations for:
865 /// - Message field access operations
866 /// - Map key access patterns
867 /// - Nested field selection chains
868 /// - No new syntax or functions are added
869 /// - Transparent performance improvements
870 ///
871 /// # Examples
872 ///
873 /// ```rust
874 /// use cel_cxx::*;
875 ///
876 /// let env = Env::builder()
877 /// .with_ext_select_optimization(true)
878 /// .build()?;
879 ///
880 /// // Field access operations may be optimized
881 /// let program = env.compile("user.profile.settings.theme")?;
882 ///
883 /// // Map access patterns may be optimized
884 /// let program2 = env.compile("config['database']['host']")?;
885 /// # Ok::<(), cel_cxx::Error>(())
886 /// ```
887 pub fn with_ext_select_optimization(mut self, enable: bool) -> Self {
888 self.options.enable_ext_select_optimization = enable;
889 self
890 }
891
892 /// Registers a function (either global or member).
893 ///
894 /// This method allows you to register custom functions that can be called
895 /// from CEL expressions. The function can be either a global function or
896 /// a member function of a type.
897 ///
898 /// # Function Registration Process
899 ///
900 /// When you register a function, the system:
901 /// 1. Extracts type information from the function signature
902 /// 2. Creates type-safe conversion wrappers
903 /// 3. Stores both the type signature and implementation
904 /// 4. Updates the function marker type to track sync/async status
905 ///
906 /// # Zero-Annotation Benefits
907 ///
908 /// Functions are registered without explicit type annotations:
909 /// - Argument types are automatically inferred
910 /// - Return types are automatically determined
911 /// - Error handling is automatically supported for `Result<T, E>` returns
912 /// - Reference parameters like `&str` are handled safely
913 ///
914 /// # Arguments
915 ///
916 /// * `name` - The name of the function as it will appear in CEL expressions
917 /// * `member` - Whether this is a member function (`true`) or global function (`false`)
918 /// * `f` - The function implementation (function pointer, closure, etc.)
919 ///
920 /// # Type Parameters
921 ///
922 /// * `F` - The function implementation type
923 /// * `Ffm` - The function marker type (sync/async) inferred from the function
924 /// * `Args` - The argument tuple type (automatically inferred)
925 ///
926 /// # Returns
927 ///
928 /// A new `EnvBuilder` with updated function marker type. If this is the first
929 /// async function registered, the marker changes from `()` to `Async`.
930 ///
931 /// # Member vs Global Functions
932 ///
933 /// ## Global Functions
934 /// Called as `function_name(args...)`:
935 /// ```text
936 /// max(a, b) // max function with two arguments
937 /// calculate(x, y, z) // calculate function with three arguments
938 /// ```
939 ///
940 /// ## Member Functions
941 /// Called as `object.method(args...)`:
942 /// ```text
943 /// text.contains(substring) // contains method on string
944 /// list.size() // size method on list
945 /// ```
946 ///
947 /// # Function Signature Support
948 ///
949 /// Supports various function signatures:
950 /// - **Simple functions**: `fn(T) -> U`
951 /// - **Functions with errors**: `fn(T) -> Result<U, E>`
952 /// - **Reference parameters**: `fn(&str, i64) -> String`
953 /// - **Multiple parameters**: Up to 10 parameters supported
954 /// - **Closures**: Move closures that capture environment
955 ///
956 /// # Errors
957 ///
958 /// Returns [`Error`] if:
959 /// - Function name conflicts with existing registration
960 /// - Function signature is invalid or unsupported
961 /// - Type inference fails
962 ///
963 /// # Examples
964 ///
965 /// ## Basic Functions
966 ///
967 /// ```rust
968 /// use cel_cxx::*;
969 ///
970 /// let builder = Env::builder()
971 /// .register_function("add", false, |a: i64, b: i64| a + b)?
972 /// .register_function("greet", false, |name: &str| format!("Hello, {}!", name))?;
973 /// # Ok::<(), cel_cxx::Error>(())
974 /// ```
975 ///
976 /// ## Member Functions
977 ///
978 /// ```rust
979 /// use cel_cxx::*;
980 ///
981 /// let builder = Env::builder()
982 /// .register_function("contains", true, |text: &str, substr: &str| text.contains(substr))?
983 /// .register_function("length", true, |text: &str| text.len() as i64)?;
984 ///
985 /// // Usage in expressions:
986 /// // text.contains("hello")
987 /// // text.length()
988 /// # Ok::<(), cel_cxx::Error>(())
989 /// ```
990 ///
991 /// ## Functions with Error Handling
992 ///
993 /// ```rust
994 /// use cel_cxx::*;
995 ///
996 /// let builder = Env::builder()
997 /// .register_function("divide", false, |a: f64, b: f64| -> Result<f64, Error> {
998 /// if b == 0.0 {
999 /// Err(Error::invalid_argument("division by zero"))
1000 /// } else {
1001 /// Ok(a / b)
1002 /// }
1003 /// })?;
1004 /// # Ok::<(), cel_cxx::Error>(())
1005 /// ```
1006 ///
1007 /// ## Closures with Captured Data
1008 ///
1009 /// ```rust
1010 /// use cel_cxx::*;
1011 ///
1012 /// let multiplier = 5;
1013 /// let threshold = 100.0;
1014 ///
1015 /// let builder = Env::builder()
1016 /// .register_function("scale", false, move |x: i64| x * multiplier)?
1017 /// .register_function("check_limit", false, move |value: f64| value < threshold)?;
1018 /// # Ok::<(), cel_cxx::Error>(())
1019 /// ```
1020 pub fn register_function<F, Ffm, Args>(
1021 mut self,
1022 name: impl Into<String>,
1023 member: bool,
1024 f: F,
1025 ) -> Result<EnvBuilder<'f, <Ffm as FnMarkerAggr<Fm>>::Output, Rm>, Error>
1026 where
1027 F: IntoFunction<'f, Ffm, Args>,
1028 Ffm: FnMarker + FnMarkerAggr<Fm>,
1029 Args: Arguments,
1030 {
1031 self.function_registry.register(name, member, f)?;
1032
1033 Ok(EnvBuilder {
1034 function_registry: self.function_registry,
1035 variable_registry: self.variable_registry,
1036 options: self.options,
1037 _fn_marker: std::marker::PhantomData,
1038 _rt_marker: std::marker::PhantomData,
1039 })
1040 }
1041
1042 /// Registers a member function.
1043 ///
1044 /// This is a convenience method for registering member functions, equivalent to
1045 /// calling `register_function(name, true, f)`. Member functions are called using
1046 /// dot notation in CEL expressions: `object.method(args...)`.
1047 ///
1048 /// # Arguments
1049 ///
1050 /// * `name` - The method name as it will appear in CEL expressions
1051 /// * `f` - The function implementation
1052 ///
1053 /// # Member Function Semantics
1054 ///
1055 /// Member functions in CEL follow these patterns:
1056 /// - First parameter is the "receiver" (the object before the dot)
1057 /// - Additional parameters become method arguments
1058 /// - Called as `receiver.method(arg1, arg2, ...)`
1059 ///
1060 /// # Examples
1061 ///
1062 /// ## String Methods
1063 ///
1064 /// ```rust
1065 /// use cel_cxx::*;
1066 ///
1067 /// let builder = Env::builder()
1068 /// .register_member_function("upper", |s: &str| s.to_uppercase())?
1069 /// .register_member_function("contains", |s: &str, substr: &str| s.contains(substr))?
1070 /// .register_member_function("repeat", |s: &str, n: i64| s.repeat(n as usize))?;
1071 ///
1072 /// // Usage in expressions:
1073 /// // "hello".upper() -> "HELLO"
1074 /// // "hello world".contains("world") -> true
1075 /// // "abc".repeat(3) -> "abcabcabc"
1076 /// # Ok::<(), cel_cxx::Error>(())
1077 /// ```
1078 ///
1079 /// ## Numeric Methods
1080 ///
1081 /// ```rust
1082 /// use cel_cxx::*;
1083 ///
1084 /// let builder = Env::builder()
1085 /// .register_member_function("abs", |x: f64| x.abs())?
1086 /// .register_member_function("pow", |x: f64, exp: f64| x.powf(exp))?;
1087 ///
1088 /// // Usage in expressions:
1089 /// // (-5.5).abs() -> 5.5
1090 /// // (2.0).pow(3.0) -> 8.0
1091 /// # Ok::<(), cel_cxx::Error>(())
1092 /// ```
1093 pub fn register_member_function<F, Ffm, Args>(
1094 mut self,
1095 name: impl Into<String>,
1096 f: F,
1097 ) -> Result<EnvBuilder<'f, <Ffm as FnMarkerAggr<Fm>>::Output, Rm>, Error>
1098 where
1099 F: IntoFunction<'f, Ffm, Args>,
1100 Ffm: FnMarker + FnMarkerAggr<Fm>,
1101 Args: Arguments,
1102 {
1103 self.function_registry.register_member(name, f)?;
1104
1105 Ok(EnvBuilder {
1106 function_registry: self.function_registry,
1107 variable_registry: self.variable_registry,
1108 options: self.options,
1109 _fn_marker: std::marker::PhantomData,
1110 _rt_marker: std::marker::PhantomData,
1111 })
1112 }
1113
1114 /// Registers a global function.
1115 ///
1116 /// This is a convenience method for registering global functions, equivalent to
1117 /// calling `register_function(name, false, f)`. Global functions are called directly
1118 /// by name in CEL expressions: `function_name(args...)`.
1119 ///
1120 /// # Arguments
1121 ///
1122 /// * `name` - The function name as it will appear in CEL expressions
1123 /// * `f` - The function implementation
1124 ///
1125 /// # Global Function Characteristics
1126 ///
1127 /// Global functions:
1128 /// - Are called directly by name without a receiver object
1129 /// - Can have 0 to 10 parameters
1130 /// - Support all CEL-compatible parameter and return types
1131 /// - Can capture environment variables (for closures)
1132 ///
1133 /// # Function Naming Guidelines
1134 ///
1135 /// - Use clear, descriptive names: `calculate_tax`, `format_date`
1136 /// - Follow CEL naming conventions (snake_case is recommended)
1137 /// - Avoid conflicts with built-in CEL functions
1138 /// - Consider namespacing for domain-specific functions: `math_sqrt`, `string_trim`
1139 ///
1140 /// # Examples
1141 ///
1142 /// ## Mathematical Functions
1143 ///
1144 /// ```rust
1145 /// use cel_cxx::*;
1146 ///
1147 /// let builder = Env::builder()
1148 /// .register_global_function("add", |a: i64, b: i64| a + b)?
1149 /// .register_global_function("multiply", |a: f64, b: f64| a * b)?
1150 /// .register_global_function("max", |a: i64, b: i64| if a > b { a } else { b })?;
1151 ///
1152 /// // Usage in expressions:
1153 /// // add(10, 20) -> 30
1154 /// // multiply(2.5, 4.0) -> 10.0
1155 /// // max(15, 8) -> 15
1156 /// # Ok::<(), cel_cxx::Error>(())
1157 /// ```
1158 ///
1159 /// ## String Processing Functions
1160 ///
1161 /// ```rust
1162 /// use cel_cxx::*;
1163 ///
1164 /// let builder = Env::builder()
1165 /// .register_global_function("concat", |a: &str, b: &str| format!("{}{}", a, b))?
1166 /// .register_global_function("trim_prefix", |s: &str, prefix: &str| {
1167 /// s.strip_prefix(prefix).unwrap_or(s).to_string()
1168 /// })?;
1169 ///
1170 /// // Usage in expressions:
1171 /// // concat("Hello, ", "World!") -> "Hello, World!"
1172 /// // trim_prefix("prefixed_text", "prefixed_") -> "text"
1173 /// # Ok::<(), cel_cxx::Error>(())
1174 /// ```
1175 ///
1176 /// ## Business Logic Functions
1177 ///
1178 /// ```rust
1179 /// use cel_cxx::*;
1180 ///
1181 /// let builder = Env::builder()
1182 /// .register_global_function("calculate_discount", |price: f64, rate: f64| {
1183 /// price * (1.0 - rate.min(1.0).max(0.0))
1184 /// })?
1185 /// .register_global_function("is_valid_email", |email: &str| {
1186 /// email.contains('@') && email.contains('.')
1187 /// })?;
1188 ///
1189 /// // Usage in expressions:
1190 /// // calculate_discount(100.0, 0.15) -> 85.0
1191 /// // is_valid_email("user@domain.com") -> true
1192 /// # Ok::<(), cel_cxx::Error>(())
1193 /// ```
1194 ///
1195 /// ## Functions with Complex Logic
1196 ///
1197 /// ```rust
1198 /// use cel_cxx::*;
1199 /// use std::collections::HashMap;
1200 ///
1201 /// // Function that processes collections
1202 /// let builder = Env::builder()
1203 /// .register_global_function("sum_positive", |numbers: Vec<i64>| {
1204 /// numbers.iter().filter(|&x| *x > 0).sum::<i64>()
1205 /// })?;
1206 ///
1207 /// // Usage in expressions:
1208 /// // sum_positive([1, -2, 3, -4, 5]) -> 9
1209 /// # Ok::<(), cel_cxx::Error>(())
1210 /// ```
1211 pub fn register_global_function<F, Ffm, Args>(
1212 mut self,
1213 name: impl Into<String>,
1214 f: F,
1215 ) -> Result<EnvBuilder<'f, <Ffm as FnMarkerAggr<Fm>>::Output, Rm>, Error>
1216 where
1217 F: IntoFunction<'f, Ffm, Args>,
1218 Ffm: FnMarker + FnMarkerAggr<Fm>,
1219 Args: Arguments,
1220 {
1221 self.function_registry.register_global(name, f)?;
1222
1223 Ok(EnvBuilder {
1224 function_registry: self.function_registry,
1225 variable_registry: self.variable_registry,
1226 options: self.options,
1227 _fn_marker: std::marker::PhantomData,
1228 _rt_marker: std::marker::PhantomData,
1229 })
1230 }
1231
1232 /// Declares a function signature without providing an implementation.
1233 ///
1234 /// This is useful when you want to declare that a function exists for
1235 /// type checking purposes, but will provide the implementation later
1236 /// via activation bindings.
1237 ///
1238 /// # Arguments
1239 ///
1240 /// * `name` - The name of the function
1241 /// * `member` - Whether this is a member function (`true`) or global function (`false`)
1242 ///
1243 /// # Type Parameters
1244 ///
1245 /// * `D` - The function declaration type that specifies the signature
1246 pub fn declare_function<D>(
1247 mut self,
1248 name: impl Into<String>,
1249 member: bool,
1250 ) -> Result<Self, Error>
1251 where
1252 D: FunctionDecl,
1253 {
1254 self.function_registry.declare::<D>(name, member)?;
1255 Ok(EnvBuilder {
1256 function_registry: self.function_registry,
1257 variable_registry: self.variable_registry,
1258 options: self.options,
1259 _fn_marker: std::marker::PhantomData,
1260 _rt_marker: std::marker::PhantomData,
1261 })
1262 }
1263
1264 /// Declares a member function signature without providing an implementation.
1265 ///
1266 /// # Arguments
1267 ///
1268 /// * `name` - The name of the member function
1269 ///
1270 /// # Type Parameters
1271 ///
1272 /// * `D` - The function declaration type that specifies the signature
1273 pub fn declare_member_function<D>(mut self, name: impl Into<String>) -> Result<Self, Error>
1274 where
1275 D: FunctionDecl,
1276 {
1277 self.function_registry.declare_member::<D>(name)?;
1278 Ok(EnvBuilder {
1279 function_registry: self.function_registry,
1280 variable_registry: self.variable_registry,
1281 options: self.options,
1282 _fn_marker: std::marker::PhantomData,
1283 _rt_marker: std::marker::PhantomData,
1284 })
1285 }
1286
1287 /// Declares a global function signature without providing an implementation.
1288 ///
1289 /// # Arguments
1290 ///
1291 /// * `name` - The name of the global function
1292 ///
1293 /// # Type Parameters
1294 ///
1295 /// * `D` - The function declaration type that specifies the signature
1296 pub fn declare_global_function<D>(mut self, name: impl Into<String>) -> Result<Self, Error>
1297 where
1298 D: FunctionDecl,
1299 {
1300 self.function_registry.declare_global::<D>(name)?;
1301 Ok(EnvBuilder {
1302 function_registry: self.function_registry,
1303 variable_registry: self.variable_registry,
1304 options: self.options,
1305 _fn_marker: std::marker::PhantomData,
1306 _rt_marker: std::marker::PhantomData,
1307 })
1308 }
1309
1310 /// Defines a constant value that can be referenced in expressions.
1311 ///
1312 /// Constants are immutable values that are resolved at compile time.
1313 ///
1314 /// # Arguments
1315 ///
1316 /// * `name` - The name of the constant
1317 /// * `value` - The constant value
1318 ///
1319 /// # Examples
1320 ///
1321 /// ```rust,no_run
1322 /// use cel_cxx::*;
1323 ///
1324 /// let builder = Env::builder()
1325 /// .define_constant("PI", 3.14159)
1326 /// .unwrap();
1327 /// # Ok::<(), cel_cxx::Error>(())
1328 /// ```
1329 pub fn define_constant<T>(mut self, name: impl Into<String>, value: T) -> Result<Self, Error>
1330 where
1331 T: IntoConstant,
1332 {
1333 self.variable_registry.define_constant(name, value)?;
1334 Ok(EnvBuilder {
1335 function_registry: self.function_registry,
1336 variable_registry: self.variable_registry,
1337 options: self.options,
1338 _fn_marker: std::marker::PhantomData,
1339 _rt_marker: std::marker::PhantomData,
1340 })
1341 }
1342
1343 /// Declares a variable of a specific type.
1344 ///
1345 /// This declares that a variable of the given name and type may be
1346 /// provided during evaluation. The actual value must be bound in
1347 /// the activation when evaluating expressions.
1348 ///
1349 /// # Arguments
1350 ///
1351 /// * `name` - The name of the variable
1352 ///
1353 /// # Type Parameters
1354 ///
1355 /// * `T` - The type of the variable
1356 ///
1357 /// # Examples
1358 ///
1359 /// ```rust,no_run
1360 /// use cel_cxx::*;
1361 ///
1362 /// let builder = Env::builder()
1363 /// .declare_variable::<String>("user_name")?
1364 /// .declare_variable::<i64>("age")?;
1365 ///
1366 /// # Ok::<(), cel_cxx::Error>(())
1367 /// ```
1368 pub fn declare_variable<T>(mut self, name: impl Into<String>) -> Result<Self, Error>
1369 where
1370 T: TypedValue,
1371 {
1372 self.variable_registry.declare::<T>(name)?;
1373 Ok(EnvBuilder {
1374 function_registry: self.function_registry,
1375 variable_registry: self.variable_registry,
1376 options: self.options,
1377 _fn_marker: std::marker::PhantomData,
1378 _rt_marker: std::marker::PhantomData,
1379 })
1380 }
1381
1382 /// Builds the environment from the configured builder.
1383 ///
1384 /// This method consumes the builder and creates the final [`Env`] instance
1385 /// that can be used to compile CEL expressions.
1386 ///
1387 /// # Returns
1388 ///
1389 /// Returns a [`Result`] containing the built [`Env`] or an [`Error`] if
1390 /// the environment could not be created.
1391 ///
1392 /// # Examples
1393 ///
1394 /// ```rust,no_run
1395 /// use cel_cxx::*;
1396 ///
1397 /// let env = Env::builder()
1398 /// .declare_variable::<String>("name")?
1399 /// .build()?;
1400 /// # Ok::<(), cel_cxx::Error>(())
1401 /// ```
1402 ///
1403 /// # Errors
1404 ///
1405 /// Returns an error if the environment configuration is invalid or
1406 /// if the underlying CEL environment cannot be created.
1407 pub fn build(self) -> Result<Env<'f, Fm, Rm>, Error> {
1408 let inner = EnvInner::new_with_registries(self.function_registry, self.variable_registry, self.options)
1409 .map_err(|ffi_status| ffi::error_to_rust(&ffi_status))?;
1410 let env = Env {
1411 inner: Arc::new(inner),
1412 _fn_marker: self._fn_marker,
1413 _rt_marker: self._rt_marker,
1414 };
1415 Ok(env)
1416 }
1417}
1418
1419#[cfg(feature = "async")]
1420#[cfg_attr(docsrs, doc(cfg(feature = "async")))]
1421const _: () = {
1422 use crate::r#async::*;
1423
1424 impl<'f, Rm: RuntimeMarker> Env<'f, (), Rm> {
1425 /// Forces conversion to an async environment.
1426 ///
1427 /// This method converts a synchronous environment to an asynchronous one,
1428 /// allowing it to work with async functions and evaluation.
1429 ///
1430 /// # Type Parameters
1431 ///
1432 /// * `Rt` - The async runtime type to use
1433 ///
1434 /// # Examples
1435 ///
1436 /// ```rust,no_run
1437 /// # #[cfg(feature = "async")]
1438 /// # {
1439 /// use cel_cxx::*;
1440 ///
1441 /// let sync_env = Env::builder().build()?;
1442 /// let async_env = sync_env.force_async();
1443 /// # }
1444 /// # Ok::<(), cel_cxx::Error>(())
1445 /// ```
1446 pub fn force_async(self) -> Env<'f, Async, Rm> {
1447 Env {
1448 inner: self.inner,
1449 _fn_marker: std::marker::PhantomData,
1450 _rt_marker: std::marker::PhantomData,
1451 }
1452 }
1453 }
1454
1455 impl<'f, Rm: RuntimeMarker> EnvBuilder<'f, (), Rm> {
1456 /// Forces conversion to an async environment builder.
1457 ///
1458 /// This method converts a synchronous environment builder to an asynchronous one,
1459 /// allowing it to register async functions and build async environments.
1460 ///
1461 /// # Examples
1462 ///
1463 /// ```rust,no_run
1464 /// # #[cfg(feature = "async")]
1465 /// # {
1466 /// use cel_cxx::*;
1467 ///
1468 /// let async_builder = Env::builder().force_async();
1469 /// # }
1470 /// ```
1471 pub fn force_async(self) -> EnvBuilder<'f, Async, Rm> {
1472 EnvBuilder {
1473 function_registry: self.function_registry,
1474 variable_registry: self.variable_registry,
1475 options: self.options,
1476 _fn_marker: std::marker::PhantomData,
1477 _rt_marker: std::marker::PhantomData,
1478 }
1479 }
1480 }
1481
1482 impl<'f, Fm: FnMarker> Env<'f, Fm, ()> {
1483 /// Sets the async runtime for this environment.
1484 ///
1485 /// This method specifies which async runtime should be used for
1486 /// asynchronous evaluation of expressions.
1487 ///
1488 /// # Type Parameters
1489 ///
1490 /// * `Rt` - The runtime type to use (must implement [`Runtime`])
1491 ///
1492 /// # Examples
1493 ///
1494 /// ```rust,no_run
1495 /// # #[cfg(feature = "async")]
1496 /// # {
1497 /// use cel_cxx::*;
1498 ///
1499 /// let env = Env::builder()
1500 /// .build()?
1501 /// .use_runtime::<Tokio>();
1502 /// # }
1503 /// # Ok::<(), cel_cxx::Error>(())
1504 /// ```
1505 pub fn use_runtime<Rt: Runtime>(self) -> Env<'f, Fm, Rt> {
1506 let inner = self.inner.clone();
1507 Env {
1508 inner,
1509 _fn_marker: self._fn_marker,
1510 _rt_marker: std::marker::PhantomData,
1511 }
1512 }
1513
1514 /// Configures the environment to use the Tokio async runtime.
1515 ///
1516 /// This is a convenience method for setting the runtime to Tokio.
1517 /// Requires the `tokio` feature to be enabled.
1518 ///
1519 /// # Examples
1520 ///
1521 /// ```rust,no_run
1522 /// # #[cfg(all(feature = "async", feature = "tokio"))]
1523 /// # {
1524 /// use cel_cxx::*;
1525 ///
1526 /// let env = Env::builder()
1527 /// .build()?
1528 /// .use_tokio();
1529 /// # }
1530 /// # Ok::<(), cel_cxx::Error>(())
1531 /// ```
1532 #[cfg(feature = "tokio")]
1533 #[cfg_attr(docsrs, doc(cfg(feature = "tokio")))]
1534 pub fn use_tokio(self) -> Env<'f, Fm, Tokio> {
1535 self.use_runtime::<Tokio>()
1536 }
1537
1538 /// Configures the environment to use the async-std runtime.
1539 ///
1540 /// This is a convenience method for setting the runtime to async-std.
1541 /// Requires the `async-std` feature to be enabled.
1542 ///
1543 /// # Examples
1544 ///
1545 /// ```rust,no_run
1546 /// # #[cfg(all(feature = "async", feature = "async-std"))]
1547 /// # {
1548 /// use cel_cxx::*;
1549 ///
1550 /// let env = Env::builder()
1551 /// .build()?
1552 /// .use_async_std();
1553 /// # }
1554 /// # Ok::<(), cel_cxx::Error>(())
1555 /// ```
1556 #[cfg(feature = "async-std")]
1557 #[cfg_attr(docsrs, doc(cfg(feature = "async-std")))]
1558 pub fn use_async_std(self) -> Env<'f, Fm, AsyncStd> {
1559 self.use_runtime::<AsyncStd>()
1560 }
1561
1562 /// Configures the environment to use the smol runtime.
1563 ///
1564 /// This is a convenience method for setting the runtime to smol.
1565 /// Requires the `smol` feature to be enabled.
1566 ///
1567 /// # Examples
1568 ///
1569 /// ```rust,no_run
1570 /// # #[cfg(feature = "async")]
1571 /// # {
1572 /// use cel_cxx::*;
1573 ///
1574 /// let env = Env::builder().use_smol();
1575 /// # }
1576 /// # Ok::<(), cel_cxx::Error>(())
1577 /// ```
1578 #[cfg(feature = "smol")]
1579 #[cfg_attr(docsrs, doc(cfg(feature = "smol")))]
1580 pub fn use_smol(self) -> Env<'f, Fm, Smol> {
1581 self.use_runtime::<Smol>()
1582 }
1583 }
1584
1585 impl<'f, Fm: FnMarker> EnvBuilder<'f, Fm, ()> {
1586 /// Sets the async runtime for the environment builder.
1587 ///
1588 /// This method specifies which async runtime should be used by
1589 /// environments built from this builder.
1590 ///
1591 /// # Type Parameters
1592 ///
1593 /// * `Rt` - The runtime type to use (must implement [`Runtime`])
1594 ///
1595 /// # Examples
1596 ///
1597 /// ```rust,no_run
1598 /// # #[cfg(feature = "async")]
1599 /// # {
1600 /// use cel_cxx::*;
1601 ///
1602 /// let builder = Env::builder().use_runtime::<Tokio>();
1603 /// # }
1604 /// ```
1605 pub fn use_runtime<Rt: Runtime>(self) -> EnvBuilder<'f, Fm, Rt> {
1606 EnvBuilder {
1607 function_registry: self.function_registry,
1608 variable_registry: self.variable_registry,
1609 options: self.options,
1610 _fn_marker: self._fn_marker,
1611 _rt_marker: std::marker::PhantomData,
1612 }
1613 }
1614
1615 /// Configures the builder to use the Tokio async runtime.
1616 ///
1617 /// This is a convenience method for setting the runtime to Tokio.
1618 /// Requires the `tokio` feature to be enabled.
1619 ///
1620 /// # Examples
1621 ///
1622 /// ```rust,no_run
1623 /// # #[cfg(all(feature = "async", feature = "tokio"))]
1624 /// # {
1625 /// use cel_cxx::*;
1626 ///
1627 /// let builder = Env::builder().use_tokio();
1628 /// # }
1629 /// ```
1630 #[cfg(feature = "tokio")]
1631 #[cfg_attr(docsrs, doc(cfg(feature = "tokio")))]
1632 pub fn use_tokio(self) -> EnvBuilder<'f, Fm, Tokio> {
1633 self.use_runtime::<Tokio>()
1634 }
1635
1636 /// Configures the builder to use the async-std runtime.
1637 ///
1638 /// This is a convenience method for setting the runtime to async-std.
1639 /// Requires the `async-std` feature to be enabled.
1640 ///
1641 /// # Examples
1642 ///
1643 /// ```rust,no_run
1644 /// # #[cfg(all(feature = "async", feature = "async-std"))]
1645 /// # {
1646 /// use cel_cxx::*;
1647 ///
1648 /// let builder = Env::builder().use_async_std();
1649 /// # }
1650 /// ```
1651 #[cfg(feature = "async-std")]
1652 #[cfg_attr(docsrs, doc(cfg(feature = "async-std")))]
1653 pub fn use_async_std(self) -> EnvBuilder<'f, Fm, AsyncStd> {
1654 self.use_runtime::<AsyncStd>()
1655 }
1656
1657 /// Configures the builder to use the smol runtime.
1658 ///
1659 /// This is a convenience method for setting the runtime to smol.
1660 /// Requires the `smol` feature to be enabled.
1661 ///
1662 /// # Examples
1663 ///
1664 /// ```rust,no_run
1665 /// # #[cfg(feature = "async")]
1666 /// # {
1667 /// use cel_cxx::*;
1668 ///
1669 /// let builder = Env::builder().use_smol();
1670 /// # }
1671 /// ```
1672 #[cfg(feature = "smol")]
1673 #[cfg_attr(docsrs, doc(cfg(feature = "smol")))]
1674 pub fn use_smol(self) -> EnvBuilder<'f, Fm, Smol> {
1675 self.use_runtime::<Smol>()
1676 }
1677 }
1678};
1679
1680impl<'f, Fm: FnMarker, Rm: RuntimeMarker> std::fmt::Debug for Env<'f, Fm, Rm> {
1681 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1682 f.debug_struct("Env").field("inner", &self.inner).finish()
1683 }
1684}
1685
1686impl<'f, Fm: FnMarker, Rm: RuntimeMarker> Clone for Env<'f, Fm, Rm> {
1687 fn clone(&self) -> Self {
1688 Env {
1689 inner: self.inner.clone(),
1690 _fn_marker: self._fn_marker,
1691 _rt_marker: self._rt_marker,
1692 }
1693 }
1694}
1695
1696impl<'f, Fm: FnMarker, Rm: RuntimeMarker> std::fmt::Debug for EnvBuilder<'f, Fm, Rm> {
1697 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1698 f.debug_struct("EnvBuilder")
1699 .field("function_registry", &self.function_registry)
1700 .field("variable_registry", &self.variable_registry)
1701 .finish()
1702 }
1703}
1704
1705impl<'f, Fm: FnMarker, Rm: RuntimeMarker> Default for EnvBuilder<'f, Fm, Rm> {
1706 fn default() -> Self {
1707 EnvBuilder {
1708 function_registry: FunctionRegistry::new(),
1709 variable_registry: VariableRegistry::new(),
1710 options: EnvInnerOptions::default(),
1711 _fn_marker: std::marker::PhantomData,
1712 _rt_marker: std::marker::PhantomData,
1713 }
1714 }
1715}