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