Skip to main content

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}