fastn_resolved/evalexpr/function/
mod.rs

1use std::fmt;
2
3use fastn_resolved::evalexpr::{error::EvalexprResult, value::Value};
4
5pub(crate) mod builtin;
6
7/// A helper trait to enable cloning through `Fn` trait objects.
8trait ClonableFn
9where
10    Self: Fn(&Value) -> EvalexprResult<Value>,
11    Self: Send + Sync + 'static,
12{
13    fn dyn_clone(&self) -> Box<dyn ClonableFn>;
14}
15
16impl<F> ClonableFn for F
17where
18    F: Fn(&Value) -> EvalexprResult<Value>,
19    F: Send + Sync + 'static,
20    F: Clone,
21{
22    fn dyn_clone(&self) -> Box<dyn ClonableFn> {
23        Box::new(self.clone()) as _
24    }
25}
26
27/// A user-defined function.
28/// Functions can be used in expressions by storing them in a `Context`.
29///
30/// # Examples
31///
32/// ```rust
33/// use fastn_resolved::evalexpr::*;
34///
35/// let mut context = HashMapContext::new();
36/// context.set_function("id".into(), Function::new(|argument| {
37///     Ok(argument.clone())
38/// })).unwrap(); // Do proper error handling here
39/// assert_eq!(eval_with_context("id(4)", &context), Ok(Value::from(4)));
40/// ```
41pub struct Function {
42    function: Box<dyn ClonableFn>,
43}
44
45impl Clone for Function {
46    fn clone(&self) -> Self {
47        Self {
48            function: self.function.dyn_clone(),
49        }
50    }
51}
52
53impl Function {
54    /// Creates a user-defined function.
55    ///
56    /// The `function` is boxed for storage.
57    pub fn new<F>(function: F) -> Self
58    where
59        F: Fn(&Value) -> EvalexprResult<Value>,
60        F: Send + Sync + 'static,
61        F: Clone,
62    {
63        Self {
64            function: Box::new(function) as _,
65        }
66    }
67
68    pub(crate) fn call(&self, argument: &Value) -> EvalexprResult<Value> {
69        (self.function)(argument)
70    }
71}
72
73impl fmt::Debug for Function {
74    fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
75        write!(f, "Function {{ [...] }}")
76    }
77}