use crate::shared::{
PtrMagic,
var::{default_deleter, pxs_VarList, pxs_VarType, pxs_VarValue},
};
use super::var::pxs_Var;
use std::{
cell::Cell, collections::HashMap, sync::{Mutex, OnceLock}
};
#[allow(non_camel_case_types)]
pub type pxs_Func = unsafe extern "C" fn(args: *mut pxs_Var) -> *mut pxs_Var;
pub struct Function {
pub name: String,
pub func: pxs_Func,
}
unsafe impl Send for Function {}
unsafe impl Sync for Function {}
pub struct FunctionLookup {
pub function_hash: HashMap<i32, Function>,
}
impl FunctionLookup {
pub fn get_function(&self, idx: i32) -> Option<&Function> {
self.function_hash.get(&idx)
}
pub fn add_function(&mut self, name: &str, func: pxs_Func) -> i32 {
self.function_hash.insert(
self.function_hash.len() as i32,
Function {
name: name.to_string(),
func,
},
);
return (self.function_hash.len() - 1) as i32;
}
}
static FUNCTION_LOOKUP: OnceLock<Mutex<FunctionLookup>> = OnceLock::new();
fn get_function_lookup() -> std::sync::MutexGuard<'static, FunctionLookup> {
FUNCTION_LOOKUP
.get_or_init(|| {
Mutex::new(FunctionLookup {
function_hash: HashMap::new(),
})
})
.lock()
.unwrap()
}
pub fn lookup_add_function(name: &str, func: pxs_Func) -> i32 {
let mut lookup = get_function_lookup();
let idx = lookup.function_hash.len();
lookup.function_hash.insert(
idx as i32,
Function {
name: name.to_string(),
func,
},
);
idx as i32
}
pub fn clear_function_lookup() {
let mut lookup = get_function_lookup();
lookup.function_hash.clear();
}
pub unsafe fn call_function(fn_idx: i32, args: Vec<pxs_Var>) -> pxs_Var {
let func = {
let fl = get_function_lookup();
let function = fl.get_function(fn_idx);
if function.is_none() {
return pxs_Var::new_null();
}
let function = function.unwrap();
function.func
};
let args = pxs_Var {
tag: pxs_VarType::pxs_List,
value: pxs_VarValue {
list_val: pxs_VarList { vars: args }.into_raw(),
},
deleter: Cell::new(default_deleter)
};
let args_ptr = args.into_raw();
unsafe {
let res = func(args_ptr);
let _ = pxs_Var::from_raw(args_ptr);
if res.is_null() {
pxs_Var::new_null()
} else {
pxs_Var::from_raw(res)
}
}
}