functions/functions.rs
1#![allow(clippy::too_many_arguments)]
2use std::sync::Arc;
3
4use bel::{
5 Context, ExecutionError, FunctionContext, Program, ResolveResult, Value, duration::Duration, extractors::This,
6};
7use time::DateTime;
8
9fn main() {
10 let program = Program::compile("add(2, 3) == 5 && ''.isEmpty() && fail()").unwrap();
11 let mut context = Context::default();
12
13 // Add functions using closures
14 context.add_function("add", |a: i64, b: i64| a + b);
15
16 // Add methods to a string type
17 context.add_function("isEmpty", is_empty);
18
19 // Use the function context to return error messages
20 context.add_function("fail", fail);
21
22 // See all the different value types you can accept in your functions
23 // context.add_function("primitives", primitives);
24
25 // Run the program
26 let result = program.execute(&context);
27 assert!(matches!(result, Err(ExecutionError::FunctionError { .. })));
28}
29
30/// A method on a string type. When added to the CEL context, this function
31/// can be called by running. We use the [`This`] extractor give us a reference
32/// to the string that this method was called on.
33///
34/// ```skip
35/// "foo".isEmpty()
36/// ```
37fn is_empty(This(s): This<Arc<String>>) -> bool {
38 s.is_empty()
39}
40
41/// A function that gives us access to the [`FunctionContext`]. All functions have
42/// can accept this context as their first argument. The context is helpful for
43/// several reasons:
44/// 1. Creating shadowed variables using cloned contexts (see the `filter` and `map`
45/// functions for example).
46/// 2. Functions that are fallible can return an error message using ftx.error(...)
47/// which attaches some helpful context for the error.
48fn fail(ftx: &FunctionContext) -> ResolveResult {
49 ftx.error("This function always fails").into()
50}
51
52/// A function that illustrates all the different types of values that are supported
53/// as arguments to a function, as well as the fact that any of these types can also
54/// be returned from a function.
55// Not registered in `main`: `u64` arguments are not supported yet (the `u64 => Value::UInt`
56// conversion is commented out in `bel/src/magic.rs`), so the line is left commented out.
57#[allow(dead_code)]
58fn primitives(
59 _a: i64,
60 _b: u64,
61 _c: f64,
62 _d: bool,
63 _e: Arc<String>,
64 _f: Arc<Vec<u8>>,
65 _g: Duration,
66 _h: DateTime,
67 _i: Arc<Vec<Value>>,
68) -> Duration {
69 Duration::ZERO
70}