cel_cxx/env/mod.rs
1use crate::function::{Arguments, FunctionDecl, FunctionRegistry, IntoFunction};
2use crate::variable::VariableRegistry;
3use crate::{FnMarker, FnMarkerAggr, IntoConstant, RuntimeMarker};
4use std::sync::Arc;
5
6mod inner;
7
8use crate::ffi;
9use crate::{Error, Program, TypedValue};
10pub(crate) use inner::EnvInner;
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 _fn_marker: std::marker::PhantomData<Fm>,
150 _rt_marker: std::marker::PhantomData<Rm>,
151}
152
153impl<'f, Fm: FnMarker, Rm: RuntimeMarker> EnvBuilder<'f, Fm, Rm> {
154 /// Creates a new environment builder.
155 ///
156 /// # Examples
157 ///
158 /// ```rust,no_run
159 /// use cel_cxx::*;
160 ///
161 /// let builder = EnvBuilder::<()>::new();
162 /// ```
163 pub fn new() -> Self {
164 EnvBuilder {
165 function_registry: FunctionRegistry::new(),
166 variable_registry: VariableRegistry::new(),
167 _fn_marker: std::marker::PhantomData,
168 _rt_marker: std::marker::PhantomData,
169 }
170 }
171}
172
173impl<'f, Fm: FnMarker, Rm: RuntimeMarker> EnvBuilder<'f, Fm, Rm> {
174 /// Registers a function (either global or member).
175 ///
176 /// This method allows you to register custom functions that can be called
177 /// from CEL expressions. The function can be either a global function or
178 /// a member function of a type.
179 ///
180 /// # Function Registration Process
181 ///
182 /// When you register a function, the system:
183 /// 1. Extracts type information from the function signature
184 /// 2. Creates type-safe conversion wrappers
185 /// 3. Stores both the type signature and implementation
186 /// 4. Updates the function marker type to track sync/async status
187 ///
188 /// # Zero-Annotation Benefits
189 ///
190 /// Functions are registered without explicit type annotations:
191 /// - Argument types are automatically inferred
192 /// - Return types are automatically determined
193 /// - Error handling is automatically supported for `Result<T, E>` returns
194 /// - Reference parameters like `&str` are handled safely
195 ///
196 /// # Arguments
197 ///
198 /// * `name` - The name of the function as it will appear in CEL expressions
199 /// * `member` - Whether this is a member function (`true`) or global function (`false`)
200 /// * `f` - The function implementation (function pointer, closure, etc.)
201 ///
202 /// # Type Parameters
203 ///
204 /// * `F` - The function implementation type
205 /// * `Ffm` - The function marker type (sync/async) inferred from the function
206 /// * `Args` - The argument tuple type (automatically inferred)
207 ///
208 /// # Returns
209 ///
210 /// A new `EnvBuilder` with updated function marker type. If this is the first
211 /// async function registered, the marker changes from `()` to `Async`.
212 ///
213 /// # Member vs Global Functions
214 ///
215 /// ## Global Functions
216 /// Called as `function_name(args...)`:
217 /// ```text
218 /// max(a, b) // max function with two arguments
219 /// calculate(x, y, z) // calculate function with three arguments
220 /// ```
221 ///
222 /// ## Member Functions
223 /// Called as `object.method(args...)`:
224 /// ```text
225 /// text.contains(substring) // contains method on string
226 /// list.size() // size method on list
227 /// ```
228 ///
229 /// # Function Signature Support
230 ///
231 /// Supports various function signatures:
232 /// - **Simple functions**: `fn(T) -> U`
233 /// - **Functions with errors**: `fn(T) -> Result<U, E>`
234 /// - **Reference parameters**: `fn(&str, i64) -> String`
235 /// - **Multiple parameters**: Up to 10 parameters supported
236 /// - **Closures**: Move closures that capture environment
237 ///
238 /// # Errors
239 ///
240 /// Returns [`Error`] if:
241 /// - Function name conflicts with existing registration
242 /// - Function signature is invalid or unsupported
243 /// - Type inference fails
244 ///
245 /// # Examples
246 ///
247 /// ## Basic Functions
248 ///
249 /// ```rust
250 /// use cel_cxx::*;
251 ///
252 /// let builder = Env::builder()
253 /// .register_function("add", false, |a: i64, b: i64| a + b)?
254 /// .register_function("greet", false, |name: &str| format!("Hello, {}!", name))?;
255 /// # Ok::<(), cel_cxx::Error>(())
256 /// ```
257 ///
258 /// ## Member Functions
259 ///
260 /// ```rust
261 /// use cel_cxx::*;
262 ///
263 /// let builder = Env::builder()
264 /// .register_function("contains", true, |text: &str, substr: &str| text.contains(substr))?
265 /// .register_function("length", true, |text: &str| text.len() as i64)?;
266 ///
267 /// // Usage in expressions:
268 /// // text.contains("hello")
269 /// // text.length()
270 /// # Ok::<(), cel_cxx::Error>(())
271 /// ```
272 ///
273 /// ## Functions with Error Handling
274 ///
275 /// ```rust
276 /// use cel_cxx::*;
277 ///
278 /// let builder = Env::builder()
279 /// .register_function("divide", false, |a: f64, b: f64| -> Result<f64, Error> {
280 /// if b == 0.0 {
281 /// Err(Error::invalid_argument("division by zero"))
282 /// } else {
283 /// Ok(a / b)
284 /// }
285 /// })?;
286 /// # Ok::<(), cel_cxx::Error>(())
287 /// ```
288 ///
289 /// ## Closures with Captured Data
290 ///
291 /// ```rust
292 /// use cel_cxx::*;
293 ///
294 /// let multiplier = 5;
295 /// let threshold = 100.0;
296 ///
297 /// let builder = Env::builder()
298 /// .register_function("scale", false, move |x: i64| x * multiplier)?
299 /// .register_function("check_limit", false, move |value: f64| value < threshold)?;
300 /// # Ok::<(), cel_cxx::Error>(())
301 /// ```
302 pub fn register_function<F, Ffm, Args>(
303 mut self,
304 name: impl Into<String>,
305 member: bool,
306 f: F,
307 ) -> Result<EnvBuilder<'f, <Ffm as FnMarkerAggr<Fm>>::Output, Rm>, Error>
308 where
309 F: IntoFunction<'f, Ffm, Args>,
310 Ffm: FnMarker + FnMarkerAggr<Fm>,
311 Args: Arguments,
312 {
313 self.function_registry.register(name, member, f)?;
314
315 Ok(EnvBuilder {
316 function_registry: self.function_registry,
317 variable_registry: self.variable_registry,
318 _fn_marker: std::marker::PhantomData,
319 _rt_marker: std::marker::PhantomData,
320 })
321 }
322
323 /// Registers a member function.
324 ///
325 /// This is a convenience method for registering member functions, equivalent to
326 /// calling `register_function(name, true, f)`. Member functions are called using
327 /// dot notation in CEL expressions: `object.method(args...)`.
328 ///
329 /// # Arguments
330 ///
331 /// * `name` - The method name as it will appear in CEL expressions
332 /// * `f` - The function implementation
333 ///
334 /// # Member Function Semantics
335 ///
336 /// Member functions in CEL follow these patterns:
337 /// - First parameter is the "receiver" (the object before the dot)
338 /// - Additional parameters become method arguments
339 /// - Called as `receiver.method(arg1, arg2, ...)`
340 ///
341 /// # Examples
342 ///
343 /// ## String Methods
344 ///
345 /// ```rust
346 /// use cel_cxx::*;
347 ///
348 /// let builder = Env::builder()
349 /// .register_member_function("upper", |s: &str| s.to_uppercase())?
350 /// .register_member_function("contains", |s: &str, substr: &str| s.contains(substr))?
351 /// .register_member_function("repeat", |s: &str, n: i64| s.repeat(n as usize))?;
352 ///
353 /// // Usage in expressions:
354 /// // "hello".upper() -> "HELLO"
355 /// // "hello world".contains("world") -> true
356 /// // "abc".repeat(3) -> "abcabcabc"
357 /// # Ok::<(), cel_cxx::Error>(())
358 /// ```
359 ///
360 /// ## Numeric Methods
361 ///
362 /// ```rust
363 /// use cel_cxx::*;
364 ///
365 /// let builder = Env::builder()
366 /// .register_member_function("abs", |x: f64| x.abs())?
367 /// .register_member_function("pow", |x: f64, exp: f64| x.powf(exp))?;
368 ///
369 /// // Usage in expressions:
370 /// // (-5.5).abs() -> 5.5
371 /// // (2.0).pow(3.0) -> 8.0
372 /// # Ok::<(), cel_cxx::Error>(())
373 /// ```
374 pub fn register_member_function<F, Ffm, Args>(
375 mut self,
376 name: impl Into<String>,
377 f: F,
378 ) -> Result<EnvBuilder<'f, <Ffm as FnMarkerAggr<Fm>>::Output, Rm>, Error>
379 where
380 F: IntoFunction<'f, Ffm, Args>,
381 Ffm: FnMarker + FnMarkerAggr<Fm>,
382 Args: Arguments,
383 {
384 self.function_registry.register_member(name, f)?;
385
386 Ok(EnvBuilder {
387 function_registry: self.function_registry,
388 variable_registry: self.variable_registry,
389 _fn_marker: std::marker::PhantomData,
390 _rt_marker: std::marker::PhantomData,
391 })
392 }
393
394 /// Registers a global function.
395 ///
396 /// This is a convenience method for registering global functions, equivalent to
397 /// calling `register_function(name, false, f)`. Global functions are called directly
398 /// by name in CEL expressions: `function_name(args...)`.
399 ///
400 /// # Arguments
401 ///
402 /// * `name` - The function name as it will appear in CEL expressions
403 /// * `f` - The function implementation
404 ///
405 /// # Global Function Characteristics
406 ///
407 /// Global functions:
408 /// - Are called directly by name without a receiver object
409 /// - Can have 0 to 10 parameters
410 /// - Support all CEL-compatible parameter and return types
411 /// - Can capture environment variables (for closures)
412 ///
413 /// # Function Naming Guidelines
414 ///
415 /// - Use clear, descriptive names: `calculate_tax`, `format_date`
416 /// - Follow CEL naming conventions (snake_case is recommended)
417 /// - Avoid conflicts with built-in CEL functions
418 /// - Consider namespacing for domain-specific functions: `math_sqrt`, `string_trim`
419 ///
420 /// # Examples
421 ///
422 /// ## Mathematical Functions
423 ///
424 /// ```rust
425 /// use cel_cxx::*;
426 ///
427 /// let builder = Env::builder()
428 /// .register_global_function("add", |a: i64, b: i64| a + b)?
429 /// .register_global_function("multiply", |a: f64, b: f64| a * b)?
430 /// .register_global_function("max", |a: i64, b: i64| if a > b { a } else { b })?;
431 ///
432 /// // Usage in expressions:
433 /// // add(10, 20) -> 30
434 /// // multiply(2.5, 4.0) -> 10.0
435 /// // max(15, 8) -> 15
436 /// # Ok::<(), cel_cxx::Error>(())
437 /// ```
438 ///
439 /// ## String Processing Functions
440 ///
441 /// ```rust
442 /// use cel_cxx::*;
443 ///
444 /// let builder = Env::builder()
445 /// .register_global_function("concat", |a: &str, b: &str| format!("{}{}", a, b))?
446 /// .register_global_function("trim_prefix", |s: &str, prefix: &str| {
447 /// s.strip_prefix(prefix).unwrap_or(s).to_string()
448 /// })?;
449 ///
450 /// // Usage in expressions:
451 /// // concat("Hello, ", "World!") -> "Hello, World!"
452 /// // trim_prefix("prefixed_text", "prefixed_") -> "text"
453 /// # Ok::<(), cel_cxx::Error>(())
454 /// ```
455 ///
456 /// ## Business Logic Functions
457 ///
458 /// ```rust
459 /// use cel_cxx::*;
460 ///
461 /// let builder = Env::builder()
462 /// .register_global_function("calculate_discount", |price: f64, rate: f64| {
463 /// price * (1.0 - rate.min(1.0).max(0.0))
464 /// })?
465 /// .register_global_function("is_valid_email", |email: &str| {
466 /// email.contains('@') && email.contains('.')
467 /// })?;
468 ///
469 /// // Usage in expressions:
470 /// // calculate_discount(100.0, 0.15) -> 85.0
471 /// // is_valid_email("user@domain.com") -> true
472 /// # Ok::<(), cel_cxx::Error>(())
473 /// ```
474 ///
475 /// ## Functions with Complex Logic
476 ///
477 /// ```rust
478 /// use cel_cxx::*;
479 /// use std::collections::HashMap;
480 ///
481 /// // Function that processes collections
482 /// let builder = Env::builder()
483 /// .register_global_function("sum_positive", |numbers: Vec<i64>| {
484 /// numbers.iter().filter(|&x| *x > 0).sum::<i64>()
485 /// })?;
486 ///
487 /// // Usage in expressions:
488 /// // sum_positive([1, -2, 3, -4, 5]) -> 9
489 /// # Ok::<(), cel_cxx::Error>(())
490 /// ```
491 pub fn register_global_function<F, Ffm, Args>(
492 mut self,
493 name: impl Into<String>,
494 f: F,
495 ) -> Result<EnvBuilder<'f, <Ffm as FnMarkerAggr<Fm>>::Output, Rm>, Error>
496 where
497 F: IntoFunction<'f, Ffm, Args>,
498 Ffm: FnMarker + FnMarkerAggr<Fm>,
499 Args: Arguments,
500 {
501 self.function_registry.register_global(name, f)?;
502
503 Ok(EnvBuilder {
504 function_registry: self.function_registry,
505 variable_registry: self.variable_registry,
506 _fn_marker: std::marker::PhantomData,
507 _rt_marker: std::marker::PhantomData,
508 })
509 }
510
511 /// Declares a function signature without providing an implementation.
512 ///
513 /// This is useful when you want to declare that a function exists for
514 /// type checking purposes, but will provide the implementation later
515 /// via activation bindings.
516 ///
517 /// # Arguments
518 ///
519 /// * `name` - The name of the function
520 /// * `member` - Whether this is a member function (`true`) or global function (`false`)
521 ///
522 /// # Type Parameters
523 ///
524 /// * `D` - The function declaration type that specifies the signature
525 pub fn declare_function<D>(
526 mut self,
527 name: impl Into<String>,
528 member: bool,
529 ) -> Result<Self, Error>
530 where
531 D: FunctionDecl,
532 {
533 self.function_registry.declare::<D>(name, member)?;
534 Ok(EnvBuilder {
535 function_registry: self.function_registry,
536 variable_registry: self.variable_registry,
537 _fn_marker: std::marker::PhantomData,
538 _rt_marker: std::marker::PhantomData,
539 })
540 }
541
542 /// Declares a member function signature without providing an implementation.
543 ///
544 /// # Arguments
545 ///
546 /// * `name` - The name of the member function
547 ///
548 /// # Type Parameters
549 ///
550 /// * `D` - The function declaration type that specifies the signature
551 pub fn declare_member_function<D>(mut self, name: impl Into<String>) -> Result<Self, Error>
552 where
553 D: FunctionDecl,
554 {
555 self.function_registry.declare_member::<D>(name)?;
556 Ok(EnvBuilder {
557 function_registry: self.function_registry,
558 variable_registry: self.variable_registry,
559 _fn_marker: std::marker::PhantomData,
560 _rt_marker: std::marker::PhantomData,
561 })
562 }
563
564 /// Declares a global function signature without providing an implementation.
565 ///
566 /// # Arguments
567 ///
568 /// * `name` - The name of the global function
569 ///
570 /// # Type Parameters
571 ///
572 /// * `D` - The function declaration type that specifies the signature
573 pub fn declare_global_function<D>(mut self, name: impl Into<String>) -> Result<Self, Error>
574 where
575 D: FunctionDecl,
576 {
577 self.function_registry.declare_global::<D>(name)?;
578 Ok(EnvBuilder {
579 function_registry: self.function_registry,
580 variable_registry: self.variable_registry,
581 _fn_marker: std::marker::PhantomData,
582 _rt_marker: std::marker::PhantomData,
583 })
584 }
585
586 /// Defines a constant value that can be referenced in expressions.
587 ///
588 /// Constants are immutable values that are resolved at compile time.
589 ///
590 /// # Arguments
591 ///
592 /// * `name` - The name of the constant
593 /// * `value` - The constant value
594 ///
595 /// # Examples
596 ///
597 /// ```rust,no_run
598 /// use cel_cxx::*;
599 ///
600 /// let builder = Env::builder()
601 /// .define_constant("PI", 3.14159)
602 /// .unwrap();
603 /// # Ok::<(), cel_cxx::Error>(())
604 /// ```
605 pub fn define_constant<T>(mut self, name: impl Into<String>, value: T) -> Result<Self, Error>
606 where
607 T: IntoConstant,
608 {
609 self.variable_registry.define_constant(name, value)?;
610 Ok(EnvBuilder {
611 function_registry: self.function_registry,
612 variable_registry: self.variable_registry,
613 _fn_marker: std::marker::PhantomData,
614 _rt_marker: std::marker::PhantomData,
615 })
616 }
617
618 /// Declares a variable of a specific type.
619 ///
620 /// This declares that a variable of the given name and type may be
621 /// provided during evaluation. The actual value must be bound in
622 /// the activation when evaluating expressions.
623 ///
624 /// # Arguments
625 ///
626 /// * `name` - The name of the variable
627 ///
628 /// # Type Parameters
629 ///
630 /// * `T` - The type of the variable
631 ///
632 /// # Examples
633 ///
634 /// ```rust,no_run
635 /// use cel_cxx::*;
636 ///
637 /// let builder = Env::builder()
638 /// .declare_variable::<String>("user_name")?
639 /// .declare_variable::<i64>("age")?;
640 ///
641 /// # Ok::<(), cel_cxx::Error>(())
642 /// ```
643 pub fn declare_variable<T>(mut self, name: impl Into<String>) -> Result<Self, Error>
644 where
645 T: TypedValue,
646 {
647 self.variable_registry.declare::<T>(name)?;
648 Ok(EnvBuilder {
649 function_registry: self.function_registry,
650 variable_registry: self.variable_registry,
651 _fn_marker: std::marker::PhantomData,
652 _rt_marker: std::marker::PhantomData,
653 })
654 }
655
656 /// Builds the environment from the configured builder.
657 ///
658 /// This method consumes the builder and creates the final [`Env`] instance
659 /// that can be used to compile CEL expressions.
660 ///
661 /// # Returns
662 ///
663 /// Returns a [`Result`] containing the built [`Env`] or an [`Error`] if
664 /// the environment could not be created.
665 ///
666 /// # Examples
667 ///
668 /// ```rust,no_run
669 /// use cel_cxx::*;
670 ///
671 /// let env = Env::builder()
672 /// .declare_variable::<String>("name")?
673 /// .build()?;
674 /// # Ok::<(), cel_cxx::Error>(())
675 /// ```
676 ///
677 /// # Errors
678 ///
679 /// Returns an error if the environment configuration is invalid or
680 /// if the underlying CEL environment cannot be created.
681 pub fn build(self) -> Result<Env<'f, Fm, Rm>, Error> {
682 let inner = EnvInner::new_with_registries(self.function_registry, self.variable_registry)
683 .map_err(|ffi_status| ffi::error_to_rust(&ffi_status))?;
684 let env = Env {
685 inner: Arc::new(inner),
686 _fn_marker: self._fn_marker,
687 _rt_marker: self._rt_marker,
688 };
689 Ok(env)
690 }
691}
692
693#[cfg(feature = "async")]
694#[cfg_attr(docsrs, doc(cfg(feature = "async")))]
695const _: () = {
696 use crate::r#async::*;
697
698 impl<'f, Rm: RuntimeMarker> Env<'f, (), Rm> {
699 /// Forces conversion to an async environment.
700 ///
701 /// This method converts a synchronous environment to an asynchronous one,
702 /// allowing it to work with async functions and evaluation.
703 ///
704 /// # Type Parameters
705 ///
706 /// * `Rt` - The async runtime type to use
707 ///
708 /// # Examples
709 ///
710 /// ```rust,no_run
711 /// # #[cfg(feature = "async")]
712 /// # {
713 /// use cel_cxx::*;
714 ///
715 /// let sync_env = Env::builder().build()?;
716 /// let async_env = sync_env.force_async();
717 /// # }
718 /// # Ok::<(), cel_cxx::Error>(())
719 /// ```
720 pub fn force_async(self) -> Env<'f, Async, Rm> {
721 Env {
722 inner: self.inner,
723 _fn_marker: std::marker::PhantomData,
724 _rt_marker: std::marker::PhantomData,
725 }
726 }
727 }
728
729 impl<'f, Rm: RuntimeMarker> EnvBuilder<'f, (), Rm> {
730 /// Forces conversion to an async environment builder.
731 ///
732 /// This method converts a synchronous environment builder to an asynchronous one,
733 /// allowing it to register async functions and build async environments.
734 ///
735 /// # Examples
736 ///
737 /// ```rust,no_run
738 /// # #[cfg(feature = "async")]
739 /// # {
740 /// use cel_cxx::*;
741 ///
742 /// let async_builder = Env::builder().force_async();
743 /// # }
744 /// ```
745 pub fn force_async(self) -> EnvBuilder<'f, Async, Rm> {
746 EnvBuilder {
747 function_registry: self.function_registry,
748 variable_registry: self.variable_registry,
749 _fn_marker: std::marker::PhantomData,
750 _rt_marker: std::marker::PhantomData,
751 }
752 }
753 }
754
755 impl<'f, Fm: FnMarker> Env<'f, Fm, ()> {
756 /// Sets the async runtime for this environment.
757 ///
758 /// This method specifies which async runtime should be used for
759 /// asynchronous evaluation of expressions.
760 ///
761 /// # Type Parameters
762 ///
763 /// * `Rt` - The runtime type to use (must implement [`Runtime`])
764 ///
765 /// # Examples
766 ///
767 /// ```rust,no_run
768 /// # #[cfg(feature = "async")]
769 /// # {
770 /// use cel_cxx::*;
771 ///
772 /// let env = Env::builder()
773 /// .build()?
774 /// .use_runtime::<Tokio>();
775 /// # }
776 /// # Ok::<(), cel_cxx::Error>(())
777 /// ```
778 pub fn use_runtime<Rt: Runtime>(self) -> Env<'f, Fm, Rt> {
779 let inner = self.inner.clone();
780 Env {
781 inner,
782 _fn_marker: self._fn_marker,
783 _rt_marker: std::marker::PhantomData,
784 }
785 }
786
787 /// Configures the environment to use the Tokio async runtime.
788 ///
789 /// This is a convenience method for setting the runtime to Tokio.
790 /// Requires the `tokio` feature to be enabled.
791 ///
792 /// # Examples
793 ///
794 /// ```rust,no_run
795 /// # #[cfg(all(feature = "async", feature = "tokio"))]
796 /// # {
797 /// use cel_cxx::*;
798 ///
799 /// let env = Env::builder()
800 /// .build()?
801 /// .use_tokio();
802 /// # }
803 /// # Ok::<(), cel_cxx::Error>(())
804 /// ```
805 #[cfg(feature = "tokio")]
806 #[cfg_attr(docsrs, doc(cfg(feature = "tokio")))]
807 pub fn use_tokio(self) -> Env<'f, Fm, Tokio> {
808 self.use_runtime::<Tokio>()
809 }
810
811 /// Configures the environment to use the async-std runtime.
812 ///
813 /// This is a convenience method for setting the runtime to async-std.
814 /// Requires the `async-std` feature to be enabled.
815 ///
816 /// # Examples
817 ///
818 /// ```rust,no_run
819 /// # #[cfg(all(feature = "async", feature = "async-std"))]
820 /// # {
821 /// use cel_cxx::*;
822 ///
823 /// let env = Env::builder()
824 /// .build()?
825 /// .use_async_std();
826 /// # }
827 /// # Ok::<(), cel_cxx::Error>(())
828 /// ```
829 #[cfg(feature = "async-std")]
830 #[cfg_attr(docsrs, doc(cfg(feature = "async-std")))]
831 pub fn use_async_std(self) -> Env<'f, Fm, AsyncStd> {
832 self.use_runtime::<AsyncStd>()
833 }
834 }
835
836 impl<'f, Fm: FnMarker> EnvBuilder<'f, Fm, ()> {
837 /// Sets the async runtime for the environment builder.
838 ///
839 /// This method specifies which async runtime should be used by
840 /// environments built from this builder.
841 ///
842 /// # Type Parameters
843 ///
844 /// * `Rt` - The runtime type to use (must implement [`Runtime`])
845 ///
846 /// # Examples
847 ///
848 /// ```rust,no_run
849 /// # #[cfg(feature = "async")]
850 /// # {
851 /// use cel_cxx::*;
852 ///
853 /// let builder = Env::builder().use_runtime::<Tokio>();
854 /// # }
855 /// ```
856 pub fn use_runtime<Rt: Runtime>(self) -> EnvBuilder<'f, Fm, Rt> {
857 EnvBuilder {
858 function_registry: self.function_registry,
859 variable_registry: self.variable_registry,
860 _fn_marker: self._fn_marker,
861 _rt_marker: std::marker::PhantomData,
862 }
863 }
864
865 /// Configures the builder to use the Tokio async runtime.
866 ///
867 /// This is a convenience method for setting the runtime to Tokio.
868 /// Requires the `tokio` feature to be enabled.
869 ///
870 /// # Examples
871 ///
872 /// ```rust,no_run
873 /// # #[cfg(all(feature = "async", feature = "tokio"))]
874 /// # {
875 /// use cel_cxx::*;
876 ///
877 /// let builder = Env::builder().use_tokio();
878 /// # }
879 /// ```
880 #[cfg(feature = "tokio")]
881 #[cfg_attr(docsrs, doc(cfg(feature = "tokio")))]
882 pub fn use_tokio(self) -> EnvBuilder<'f, Fm, Tokio> {
883 self.use_runtime::<Tokio>()
884 }
885
886 /// Configures the builder to use the async-std runtime.
887 ///
888 /// This is a convenience method for setting the runtime to async-std.
889 /// Requires the `async-std` feature to be enabled.
890 ///
891 /// # Examples
892 ///
893 /// ```rust,no_run
894 /// # #[cfg(all(feature = "async", feature = "async-std"))]
895 /// # {
896 /// use cel_cxx::*;
897 ///
898 /// let builder = Env::builder().use_async_std();
899 /// # }
900 /// ```
901 #[cfg(feature = "async-std")]
902 #[cfg_attr(docsrs, doc(cfg(feature = "async-std")))]
903 pub fn use_async_std(self) -> EnvBuilder<'f, Fm, AsyncStd> {
904 self.use_runtime::<AsyncStd>()
905 }
906 }
907};
908
909impl<'f, Fm: FnMarker, Rm: RuntimeMarker> std::fmt::Debug for Env<'f, Fm, Rm> {
910 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
911 f.debug_struct("Env").field("inner", &self.inner).finish()
912 }
913}
914
915impl<'f, Fm: FnMarker, Rm: RuntimeMarker> Clone for Env<'f, Fm, Rm> {
916 fn clone(&self) -> Self {
917 Env {
918 inner: self.inner.clone(),
919 _fn_marker: self._fn_marker,
920 _rt_marker: self._rt_marker,
921 }
922 }
923}
924
925impl<'f, Fm: FnMarker, Rm: RuntimeMarker> std::fmt::Debug for EnvBuilder<'f, Fm, Rm> {
926 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
927 f.debug_struct("EnvBuilder")
928 .field("function_registry", &self.function_registry)
929 .field("variable_registry", &self.variable_registry)
930 .finish()
931 }
932}
933
934impl<'f, Fm: FnMarker, Rm: RuntimeMarker> Default for EnvBuilder<'f, Fm, Rm> {
935 fn default() -> Self {
936 EnvBuilder {
937 function_registry: FunctionRegistry::new(),
938 variable_registry: VariableRegistry::new(),
939 _fn_marker: std::marker::PhantomData,
940 _rt_marker: std::marker::PhantomData,
941 }
942 }
943}