use crate::value::{FuncType, Val};
use fizzyx_sys as sys;
use std::panic::{AssertUnwindSafe, catch_unwind};
pub(crate) type HostFn = Box<dyn Fn(&[Val], &mut [Val])>;
pub(crate) struct HostFunc {
ty: FuncType,
func: HostFn,
}
impl HostFunc {
pub(crate) fn new(ty: FuncType, func: HostFn) -> Self {
Self { ty, func }
}
pub(crate) fn ty(&self) -> &FuncType {
&self.ty
}
}
pub(crate) unsafe extern "C" fn trampoline(
host_ctx: *mut core::ffi::c_void,
_instance: *mut sys::FizzyInstance,
args: *const sys::FizzyValue,
_exec_ctx: *mut sys::FizzyExecutionContext,
) -> sys::FizzyExecutionResult {
let outcome = catch_unwind(AssertUnwindSafe(|| {
let host_func = unsafe { &*(host_ctx as *const HostFunc) };
let params_ty = host_func.ty().params();
let results_ty = host_func.ty().results();
let mut params = Vec::with_capacity(params_ty.len());
for (i, &ty) in params_ty.iter().enumerate() {
let raw = unsafe { *args.add(i) };
params.push(Val::from_sys(raw, ty));
}
let mut results: Vec<Val> = results_ty
.iter()
.map(|&ty| Val::default_for_ty(ty))
.collect();
(host_func.func)(¶ms, &mut results);
match results.first() {
Some(value) => sys::FizzyExecutionResult {
trapped: false,
has_value: true,
value: value.to_sys(),
},
None => sys::FizzyExecutionResult {
trapped: false,
has_value: false,
value: sys::FizzyValue { i64_: 0 },
},
}
}));
outcome.unwrap_or(sys::FizzyExecutionResult {
trapped: true,
has_value: false,
value: sys::FizzyValue { i64_: 0 },
})
}