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