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