1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119
//! Module which defines the function registration mechanism. #![cfg(not(feature = "no_function"))] #![allow(non_snake_case)] use crate::any::Variant; use crate::engine::Engine; use crate::error::ParseError; use crate::parser::AST; use crate::result::EvalAltResult; use crate::scope::Scope; use crate::stdlib::{boxed::Box, string::ToString}; /// Trait to create a Rust anonymous function from a script. pub trait Func<ARGS, RET> { type Output; /// Create a Rust anonymous function from an `AST`. /// The `Engine` and `AST` are consumed and basically embedded into the closure. /// /// # Examples /// /// ``` /// # fn main() -> Result<(), Box<rhai::EvalAltResult>> { /// use rhai::{Engine, Func}; // use 'Func' for 'create_from_ast' /// /// let engine = Engine::new(); // create a new 'Engine' just for this /// /// let ast = engine.compile("fn calc(x, y) { x + len(y) < 42 }")?; /// /// // Func takes two type parameters: /// // 1) a tuple made up of the types of the script function's parameters /// // 2) the return type of the script function /// // /// // 'func' will have type Box<dyn Fn(i64, String) -> Result<bool, Box<EvalAltResult>>> and is callable! /// let func = Func::<(i64, String), bool>::create_from_ast( /// // ^^^^^^^^^^^^^ function parameter types in tuple /// /// engine, // the 'Engine' is consumed into the closure /// ast, // the 'AST' /// "calc" // the entry-point function name /// ); /// /// func(123, "hello".to_string())? == false; // call the anonymous function /// # Ok(()) /// # } fn create_from_ast(self, ast: AST, entry_point: &str) -> Self::Output; /// Create a Rust anonymous function from a script. /// The `Engine` is consumed and basically embedded into the closure. /// /// # Examples /// /// ``` /// # fn main() -> Result<(), Box<rhai::EvalAltResult>> { /// use rhai::{Engine, Func}; // use 'Func' for 'create_from_script' /// /// let engine = Engine::new(); // create a new 'Engine' just for this /// /// let script = "fn calc(x, y) { x + len(y) < 42 }"; /// /// // Func takes two type parameters: /// // 1) a tuple made up of the types of the script function's parameters /// // 2) the return type of the script function /// // /// // 'func' will have type Box<dyn Fn(i64, String) -> Result<bool, Box<EvalAltResult>>> and is callable! /// let func = Func::<(i64, String), bool>::create_from_script( /// // ^^^^^^^^^^^^^ function parameter types in tuple /// /// engine, // the 'Engine' is consumed into the closure /// script, // the script, notice number of parameters must match /// "calc" // the entry-point function name /// )?; /// /// func(123, "hello".to_string())? == false; // call the anonymous function /// # Ok(()) /// # } /// ``` fn create_from_script( self, script: &str, entry_point: &str, ) -> Result<Self::Output, ParseError>; } macro_rules! def_anonymous_fn { () => { def_anonymous_fn!(imp); }; (imp $($par:ident),*) => { impl<$($par: Variant + Clone,)* RET: Variant + Clone> Func<($($par,)*), RET> for Engine { #[cfg(feature = "sync")] type Output = Box<dyn Fn($($par),*) -> Result<RET, Box<EvalAltResult>> + Send + Sync>; #[cfg(not(feature = "sync"))] type Output = Box<dyn Fn($($par),*) -> Result<RET, Box<EvalAltResult>>>; fn create_from_ast(self, ast: AST, entry_point: &str) -> Self::Output { let fn_name = entry_point.to_string(); Box::new(move |$($par: $par),*| { self.call_fn(&mut Scope::new(), &ast, &fn_name, ($($par,)*)) }) } fn create_from_script(self, script: &str, entry_point: &str) -> Result<Self::Output, ParseError> { let ast = self.compile(script)?; Ok(Func::<($($par,)*), RET>::create_from_ast(self, ast, entry_point)) } } }; ($p0:ident $(, $p:ident)*) => { def_anonymous_fn!(imp $p0 $(, $p)*); def_anonymous_fn!($($p),*); }; } def_anonymous_fn!(A, B, C, D, E, F, G, H, J, K, L, M, N, P, Q, R, S, T, U, V);