use alloc::boxed::Box;
use alloc::vec::Vec;
use crate::runtime::{RuntimeError, RuntimeErrorKind, Value, execute_func_in};
use crate::types::FuncType;
type HostClosure = Box<dyn FnMut(&[Value]) -> Result<Vec<Value>, RuntimeError>>;
pub struct HostFunction {
ty: FuncType,
func: HostClosure,
}
impl HostFunction {
pub fn new(
ty: FuncType,
func: impl FnMut(&[Value]) -> Result<Vec<Value>, RuntimeError> + 'static,
) -> Self {
Self {
ty,
func: Box::new(func),
}
}
pub fn ty(&self) -> &FuncType {
&self.ty
}
pub fn call(&mut self, args: &[Value]) -> Result<Vec<Value>, RuntimeError> {
(self.func)(args)
}
}
impl core::fmt::Debug for HostFunction {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
f.debug_struct("HostFunction")
.field("ty", &self.ty)
.finish()
}
}
pub fn link_func(
module: alloc::rc::Rc<crate::lower::RegModule>,
store: alloc::rc::Rc<core::cell::RefCell<crate::runtime::Store>>,
func_idx: crate::types::FuncIdx,
ty: FuncType,
) -> HostFunction {
HostFunction::new(ty, move |args| {
let Some(func) = module.funcs.iter().find(|func| func.idx == func_idx) else {
return Err(RuntimeError {
kind: RuntimeErrorKind::UnknownFunction { func: func_idx.0 },
});
};
let store = store.try_borrow().map_err(|_| RuntimeError {
kind: RuntimeErrorKind::ReentrantStore,
})?;
execute_func_in(Some(&module), Some(&*store), func, args, 0)
})
}