diff --git a/src/call.rs b/src/call.rs new file mode 100644 index 00000000..cf3313e3 --- /dev/null +++ b/src/call.rs @@ -0,0 +1,36 @@ +//! Helper module which defines `FnArgs` +//! to make function calling easier. + +use any::Any; + +pub trait FunArgs<'a> { + fn into_vec(self) -> Vec<&'a mut Any>; +} + +macro_rules! impl_args { + ($($p:ident),*) => { + impl<'a, $($p),*> FunArgs<'a> for ($(&'a mut $p,)*) + where + $($p: Any + Clone),* + { + fn into_vec(self) -> Vec<&'a mut Any> { + let ($($p,)*) = self; + + let mut v = Vec::new(); + $(v.push($p as &mut Any);)* + + v + } + } + + impl_args!(@pop $($p),*); + }; + (@pop) => { + }; + (@pop $head:ident $(, $tail:ident)*) => { + impl_args!($($tail),*); + }; +} + +#[cfg_attr(rustfmt, rustfmt_skip)] +impl_args!(A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S); diff --git a/src/engine.rs b/src/engine.rs index 34c10d6f..88563a45 100644 --- a/src/engine.rs +++ b/src/engine.rs @@ -9,6 +9,7 @@ use std::ops::{Add, BitAnd, BitOr, BitXor, Deref, Div, Mul, Neg, Rem, Shl, Shr, use any::{Any, AnyExt}; use fn_register::{Mut, RegisterFn}; use parser::{lex, parse, Expr, FnDef, Stmt}; +use call::FunArgs; #[derive(Debug)] pub enum EvalAltResult { @@ -136,6 +137,20 @@ pub type FnAny = Fn(Vec<&mut Any>) -> Result, EvalAltResult>; pub type Scope = Vec<(String, Box)>; impl Engine { + pub fn call_fn<'a, I, A, T>(&self, ident: I, args: A) -> Result + where + I: Into, + A: FunArgs<'a>, + T: Any + Clone, + { + self.call_fn_raw(ident.into(), args.into_vec()) + .and_then(|b| { + b.downcast() + .map(|b| *b) + .map_err(|_| EvalAltResult::ErrorMismatchOutputType) + }) + } + /// Universal method for calling functions, that are either /// registered with the `Engine` or written in Rhai pub fn call_fn_raw( @@ -151,11 +166,7 @@ impl Engine { let spec = FnSpec { ident: ident.clone(), - args: Some( - args.iter() - .map(|a| ::type_id(&**a)) - .collect(), - ), + args: Some(args.iter().map(|a| ::type_id(&**a)).collect()), }; let spec1 = FnSpec { ident, args: None }; @@ -241,7 +252,9 @@ impl Engine { let mut args: Vec> = args.iter() .map(|arg| self.eval_expr(scope, arg)) .collect::, _>>()?; - let args = once(this_ptr).chain(args.iter_mut().map(|b| b.as_mut())).collect(); + let args = once(this_ptr) + .chain(args.iter_mut().map(|b| b.as_mut())) + .collect(); self.call_fn_raw(fn_name.to_owned(), args) } diff --git a/src/fn_register.rs b/src/fn_register.rs index e02ce893..ad4fbe03 100644 --- a/src/fn_register.rs +++ b/src/fn_register.rs @@ -65,4 +65,4 @@ macro_rules! def_register { } #[cfg_attr(rustfmt, rustfmt_skip)] -def_register!(A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S, T, U, V, W, X, Y, Z); +def_register!(A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S);