use crate::FamlValue;
use std::collections::HashMap;
use std::marker::PhantomData;
use std::sync::{LazyLock, Mutex};
pub trait FasCallable: Send + Sync {
fn call(&self, args: Vec<FamlValue>) -> FamlValue;
fn clone_(&self) -> Box<dyn FasCallable + 'static>;
fn get_arg_count(&self) -> usize;
}
impl std::fmt::Debug for dyn FasCallable {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.write_str("FasCallable")
}
}
pub trait FasToWrapper<T> {
type Output: FasCallable + 'static;
fn convert(self) -> Self::Output;
}
macro_rules! calc_arg_count {
()=>{
0
};
($id_eat:ident $($id:ident)*) => {
1 + calc_arg_count!($($id)*)
};
}
macro_rules! FasWrapper {
($sname:ident) => {
pub struct $sname<T: Fn() -> R, R>(T, PhantomData<R>);
impl<T, R> FasCallable for $sname<T, R>
where
T: Fn() -> R + Clone + Send + Sync + 'static,
R: Into<FamlValue> + Send + Sync + 'static,
{
fn call(&self, _args: Vec<FamlValue>) -> FamlValue {
let r = (self.0)();
r.into()
}
fn clone_(&self) -> Box<dyn FasCallable + 'static> {
let copy = Self(self.0.clone(), PhantomData);
Box::new(copy)
}
fn get_arg_count(&self) -> usize {
0
}
}
impl<T, R> FasToWrapper<R> for T
where
T: Fn() -> R + Clone + Send + Sync + 'static,
R: Into<FamlValue> + Send + Sync + 'static,
{
type Output = $sname<T, R>;
fn convert(self) -> Self::Output {
$sname(self, PhantomData)
}
}
};
($sname:ident $($name1:ident) *) => {
pub struct $sname<T: Fn($($name1),*) -> R, $($name1),*, R>(T, PhantomData<($($name1),*, R)>);
impl<T, $($name1), * ,R> FasCallable for $sname<T, $($name1),*, R>
where
T: Fn($($name1), *) -> R + Clone + Send + Sync + 'static,
$($name1: From<FamlValue> + Send + Sync + 'static),*,
R: Into<FamlValue> + Send + Sync + 'static,
{
#[allow(non_snake_case)]
fn call(&self, args: Vec<FamlValue>) -> FamlValue {
let r = {
let mut index = 0;
$(let $name1 = $name1::from(args[index].clone());index+=1;)*
let _ = index;
(self.0)($($name1),*)
};
r.into()
}
fn clone_(&self) -> Box<dyn FasCallable + 'static> {
let copy = Self(self.0.clone(), PhantomData);
Box::new(copy)
}
fn get_arg_count(&self) -> usize {
calc_arg_count!($($name1)*)
}
}
impl<T, $($name1,)* R> FasToWrapper<($($name1,)* R)> for T
where
T: Fn($($name1,)*) -> R + Clone + Send + Sync + 'static,
$($name1: From<FamlValue> + Send + Sync + 'static,)*
R: Into<FamlValue> + Send + Sync + 'static,
{
type Output = $sname<T, $($name1,)* R>;
fn convert(self) -> Self::Output {
$sname(self, PhantomData)
}
}
};
}
FasWrapper!(FuncWrapper0);
FasWrapper!(FuncWrapper1 T0);
FasWrapper!(FuncWrapper2 T0 T1);
FasWrapper!(FuncWrapper3 T0 T1 T2);
FasWrapper!(FuncWrapper4 T0 T1 T2 T3);
FasWrapper!(FuncWrapper5 T0 T1 T2 T3 T4);
FasWrapper!(FuncWrapper6 T0 T1 T2 T3 T4 T5);
FasWrapper!(FuncWrapper7 T0 T1 T2 T3 T4 T5 T6 );
FasWrapper!(FuncWrapper8 T0 T1 T2 T3 T4 T5 T6 T7);
FasWrapper!(FuncWrapper9 T0 T1 T2 T3 T4 T5 T6 T7 T8);
impl Clone for Box<dyn FasCallable + 'static> {
fn clone(&self) -> Self {
self.clone_()
}
}
pub struct Native {}
impl Native {
pub fn add_func<T: FasToWrapper<U> + 'static, U>(name: impl Into<String>, func: T) {
let func: Box<dyn FasCallable + 'static> = Box::new(func.convert());
if let Ok(mut funcs) = NATIVE_FUNCS.lock() {
funcs.insert(name.into(), func);
}
}
pub fn get_func(name: &str) -> Option<Box<dyn FasCallable + 'static>> {
if let Ok(funcs) = NATIVE_FUNCS.lock() {
funcs.get(name).cloned()
} else {
None
}
}
}
pub static NATIVE_FUNCS: LazyLock<Mutex<HashMap<String, Box<dyn FasCallable + 'static>>>> =
LazyLock::new(|| Mutex::new(HashMap::new()));