Extract function registration into a macro to prepare for future packages support.
This commit is contained in:
parent
9015499722
commit
642533aef6
@ -127,6 +127,60 @@ macro_rules! count_args {
|
|||||||
( $head:ident $($tail:ident)* ) => { 1_usize + count_args!($($tail)*) };
|
( $head:ident $($tail:ident)* ) => { 1_usize + count_args!($($tail)*) };
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// This macro creates a closure wrapping a registered function.
|
||||||
|
macro_rules! make_func {
|
||||||
|
($fn_name:ident : $fn:ident : $map:expr ; $($par:ident => $clone:expr),*) => {
|
||||||
|
// ^ function name
|
||||||
|
// ^ function pointer
|
||||||
|
// ^ result mapping function
|
||||||
|
// ^ function parameter generic type name (A, B, C etc.)
|
||||||
|
// ^ dereferencing function
|
||||||
|
|
||||||
|
move |args: &mut FnCallArgs, pos: Position| {
|
||||||
|
// Check for length at the beginning to avoid per-element bound checks.
|
||||||
|
const NUM_ARGS: usize = count_args!($($par)*);
|
||||||
|
|
||||||
|
if args.len() != NUM_ARGS {
|
||||||
|
return Err(Box::new(EvalAltResult::ErrorFunctionArgsMismatch($fn_name.clone(), NUM_ARGS, args.len(), pos)));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[allow(unused_variables, unused_mut)]
|
||||||
|
let mut drain = args.iter_mut();
|
||||||
|
$(
|
||||||
|
// Downcast every element, return in case of a type mismatch
|
||||||
|
let $par: &mut $par = drain.next().unwrap().downcast_mut().unwrap();
|
||||||
|
)*
|
||||||
|
|
||||||
|
// Call the user-supplied function using ($clone) to
|
||||||
|
// potentially clone the value, otherwise pass the reference.
|
||||||
|
let r = $fn($(($clone)($par)),*);
|
||||||
|
$map(r, pos)
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/// To Dynamic mapping function.
|
||||||
|
#[inline]
|
||||||
|
fn map_dynamic<T: Variant + Clone>(data: T, _pos: Position) -> Result<Dynamic, Box<EvalAltResult>> {
|
||||||
|
Ok(data.into_dynamic())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// To Dynamic mapping function.
|
||||||
|
#[inline]
|
||||||
|
fn map_identity(data: Dynamic, _pos: Position) -> Result<Dynamic, Box<EvalAltResult>> {
|
||||||
|
Ok(data)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// To Result<Dynamic, EvalAltResult> mapping function.
|
||||||
|
#[inline]
|
||||||
|
fn map_result<T: Variant + Clone>(
|
||||||
|
data: Result<T, EvalAltResult>,
|
||||||
|
pos: Position,
|
||||||
|
) -> Result<Dynamic, Box<EvalAltResult>> {
|
||||||
|
data.map(|v| v.into_dynamic())
|
||||||
|
.map_err(|err| Box::new(err.set_position(pos)))
|
||||||
|
}
|
||||||
|
|
||||||
macro_rules! def_register {
|
macro_rules! def_register {
|
||||||
() => {
|
() => {
|
||||||
def_register!(imp);
|
def_register!(imp);
|
||||||
@ -150,28 +204,7 @@ macro_rules! def_register {
|
|||||||
{
|
{
|
||||||
fn register_fn(&mut self, name: &str, f: FN) {
|
fn register_fn(&mut self, name: &str, f: FN) {
|
||||||
let fn_name = name.to_string();
|
let fn_name = name.to_string();
|
||||||
|
let func = make_func!(fn_name : f : map_dynamic ; $($par => $clone),*);
|
||||||
let func = move |args: &mut FnCallArgs, pos: Position| {
|
|
||||||
// Check for length at the beginning to avoid per-element bound checks.
|
|
||||||
const NUM_ARGS: usize = count_args!($($par)*);
|
|
||||||
|
|
||||||
if args.len() != NUM_ARGS {
|
|
||||||
return Err(Box::new(EvalAltResult::ErrorFunctionArgsMismatch(fn_name.clone(), NUM_ARGS, args.len(), pos)));
|
|
||||||
}
|
|
||||||
|
|
||||||
#[allow(unused_variables, unused_mut)]
|
|
||||||
let mut drain = args.iter_mut();
|
|
||||||
$(
|
|
||||||
// Downcast every element, return in case of a type mismatch
|
|
||||||
let $par: &mut $par = drain.next().unwrap().downcast_mut().unwrap();
|
|
||||||
)*
|
|
||||||
|
|
||||||
// Call the user-supplied function using ($clone) to
|
|
||||||
// potentially clone the value, otherwise pass the reference.
|
|
||||||
let r = f($(($clone)($par)),*);
|
|
||||||
Ok(r.into_dynamic())
|
|
||||||
};
|
|
||||||
|
|
||||||
self.register_fn_raw(name, vec![$(TypeId::of::<$par>()),*], Box::new(func));
|
self.register_fn_raw(name, vec![$(TypeId::of::<$par>()),*], Box::new(func));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -188,26 +221,7 @@ macro_rules! def_register {
|
|||||||
{
|
{
|
||||||
fn register_dynamic_fn(&mut self, name: &str, f: FN) {
|
fn register_dynamic_fn(&mut self, name: &str, f: FN) {
|
||||||
let fn_name = name.to_string();
|
let fn_name = name.to_string();
|
||||||
|
let func = make_func!(fn_name : f : map_identity ; $($par => $clone),*);
|
||||||
let func = move |args: &mut FnCallArgs, pos: Position| {
|
|
||||||
// Check for length at the beginning to avoid per-element bound checks.
|
|
||||||
const NUM_ARGS: usize = count_args!($($par)*);
|
|
||||||
|
|
||||||
if args.len() != NUM_ARGS {
|
|
||||||
return Err(Box::new(EvalAltResult::ErrorFunctionArgsMismatch(fn_name.clone(), NUM_ARGS, args.len(), pos)));
|
|
||||||
}
|
|
||||||
|
|
||||||
#[allow(unused_variables, unused_mut)]
|
|
||||||
let mut drain = args.iter_mut();
|
|
||||||
$(
|
|
||||||
// Downcast every element, return in case of a type mismatch
|
|
||||||
let $par: &mut $par = drain.next().unwrap().downcast_mut().unwrap();
|
|
||||||
)*
|
|
||||||
|
|
||||||
// Call the user-supplied function using ($clone) to
|
|
||||||
// potentially clone the value, otherwise pass the reference.
|
|
||||||
Ok(f($(($clone)($par)),*))
|
|
||||||
};
|
|
||||||
self.register_fn_raw(name, vec![$(TypeId::of::<$par>()),*], Box::new(func));
|
self.register_fn_raw(name, vec![$(TypeId::of::<$par>()),*], Box::new(func));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -225,27 +239,7 @@ macro_rules! def_register {
|
|||||||
{
|
{
|
||||||
fn register_result_fn(&mut self, name: &str, f: FN) {
|
fn register_result_fn(&mut self, name: &str, f: FN) {
|
||||||
let fn_name = name.to_string();
|
let fn_name = name.to_string();
|
||||||
|
let func = make_func!(fn_name : f : map_result ; $($par => $clone),*);
|
||||||
let func = move |args: &mut FnCallArgs, pos: Position| {
|
|
||||||
// Check for length at the beginning to avoid per-element bound checks.
|
|
||||||
const NUM_ARGS: usize = count_args!($($par)*);
|
|
||||||
|
|
||||||
if args.len() != NUM_ARGS {
|
|
||||||
return Err(Box::new(EvalAltResult::ErrorFunctionArgsMismatch(fn_name.clone(), NUM_ARGS, args.len(), pos)));
|
|
||||||
}
|
|
||||||
|
|
||||||
#[allow(unused_variables, unused_mut)]
|
|
||||||
let mut drain = args.iter_mut();
|
|
||||||
$(
|
|
||||||
// Downcast every element, return in case of a type mismatch
|
|
||||||
let $par: &mut $par = drain.next().unwrap().downcast_mut().unwrap();
|
|
||||||
)*
|
|
||||||
|
|
||||||
// Call the user-supplied function using ($clone) to
|
|
||||||
// potentially clone the value, otherwise pass the reference.
|
|
||||||
f($(($clone)($par)),*).map(|r| r.into_dynamic())
|
|
||||||
.map_err(|err| Box::new(err.set_position(pos)))
|
|
||||||
};
|
|
||||||
self.register_fn_raw(name, vec![$(TypeId::of::<$par>()),*], Box::new(func));
|
self.register_fn_raw(name, vec![$(TypeId::of::<$par>()),*], Box::new(func));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user