#![allow(non_snake_case)]
use crate::any::{Dynamic, Variant};
use crate::engine::{calc_fn_spec, Engine, FnCallArgs};
use crate::result::EvalAltResult;
use crate::token::Position;
use crate::stdlib::{any::TypeId, boxed::Box, string::ToString};
pub trait RegisterFn<FN, ARGS, RET> {
fn register_fn(&mut self, name: &str, f: FN);
}
pub trait RegisterDynamicFn<FN, ARGS> {
fn register_dynamic_fn(&mut self, name: &str, f: FN);
}
pub trait RegisterResultFn<FN, ARGS, RET> {
fn register_result_fn(&mut self, name: &str, f: FN);
}
pub struct Mut<T>(T);
#[inline]
pub fn identity<T>(data: &mut T) -> &mut T {
data
}
#[inline]
pub fn cloned<T: Clone>(data: &mut T) -> T {
data.clone()
}
macro_rules! count_args {
() => { 0_usize };
( $head:ident $($tail:ident)* ) => { 1_usize + count_args!($($tail)*) };
}
macro_rules! make_func {
($fn_name:ident : $fn:ident : $map:expr ; $($par:ident => $clone:expr),*) => {
move |args: &mut FnCallArgs, pos: Position| {
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();
$(
let $par: &mut $par = drain.next().unwrap().downcast_mut().unwrap();
)*
let r = $fn($(($clone)($par)),*);
$map(r, pos)
};
};
}
#[inline]
pub fn map_dynamic<T: Variant + Clone>(
data: T,
_pos: Position,
) -> Result<Dynamic, Box<EvalAltResult>> {
Ok(data.into_dynamic())
}
#[inline]
pub fn map_identity(data: Dynamic, _pos: Position) -> Result<Dynamic, Box<EvalAltResult>> {
Ok(data)
}
#[inline]
pub fn map_result<T: Variant + Clone>(
data: Result<T, Box<EvalAltResult>>,
pos: Position,
) -> Result<Dynamic, Box<EvalAltResult>> {
data.map(|v| v.into_dynamic())
.map_err(|err| EvalAltResult::set_position(err, pos))
}
macro_rules! def_register {
() => {
def_register!(imp);
};
(imp $($par:ident => $mark:ty => $param:ty => $clone:expr),*) => {
impl<
$($par: Variant + Clone,)*
#[cfg(feature = "sync")]
FN: Fn($($param),*) -> RET + Send + Sync + 'static,
#[cfg(not(feature = "sync"))]
FN: Fn($($param),*) -> RET + 'static,
RET: Variant + Clone
> RegisterFn<FN, ($($mark,)*), RET> for Engine
{
fn register_fn(&mut self, name: &str, f: FN) {
let fn_name = name.to_string();
let func = make_func!(fn_name : f : map_dynamic ; $($par => $clone),*);
let hash = calc_fn_spec(name, [$(TypeId::of::<$par>()),*].iter().cloned());
self.functions.insert(hash, Box::new(func));
}
}
impl<
$($par: Variant + Clone,)*
#[cfg(feature = "sync")]
FN: Fn($($param),*) -> Dynamic + Send + Sync + 'static,
#[cfg(not(feature = "sync"))]
FN: Fn($($param),*) -> Dynamic + 'static,
> RegisterDynamicFn<FN, ($($mark,)*)> for Engine
{
fn register_dynamic_fn(&mut self, name: &str, f: FN) {
let fn_name = name.to_string();
let func = make_func!(fn_name : f : map_identity ; $($par => $clone),*);
let hash = calc_fn_spec(name, [$(TypeId::of::<$par>()),*].iter().cloned());
self.functions.insert(hash, Box::new(func));
}
}
impl<
$($par: Variant + Clone,)*
#[cfg(feature = "sync")]
FN: Fn($($param),*) -> Result<RET, Box<EvalAltResult>> + Send + Sync + 'static,
#[cfg(not(feature = "sync"))]
FN: Fn($($param),*) -> Result<RET, Box<EvalAltResult>> + 'static,
RET: Variant + Clone
> RegisterResultFn<FN, ($($mark,)*), RET> for Engine
{
fn register_result_fn(&mut self, name: &str, f: FN) {
let fn_name = name.to_string();
let func = make_func!(fn_name : f : map_result ; $($par => $clone),*);
let hash = calc_fn_spec(name, [$(TypeId::of::<$par>()),*].iter().cloned());
self.functions.insert(hash, Box::new(func));
}
}
};
($p0:ident $(, $p:ident)*) => {
def_register!(imp $p0 => $p0 => $p0 => cloned $(, $p => $p => $p => cloned)*);
def_register!(imp $p0 => Mut<$p0> => &mut $p0 => identity $(, $p => $p => $p => cloned)*);
def_register!($($p),*);
};
}
#[rustfmt::skip]
def_register!(A, B, C, D, E, F, G, H, J, K, L, M, N, P, Q, R, S, T, U, V);