use crate::error::{Error, Result};
use crate::instance::Instance;
use crate::value::{FuncType, Val};
use fizzyx_sys as sys;
#[derive(Debug, Clone)]
pub struct Func {
func_idx: u32,
ty: FuncType,
}
impl Func {
pub(crate) fn new(func_idx: u32, ty: FuncType) -> Self {
Self { func_idx, ty }
}
pub fn ty(&self) -> &FuncType {
&self.ty
}
pub fn call(&self, instance: &mut Instance, params: &[Val], results: &mut [Val]) -> Result<()> {
let expected_params = self.ty.params();
let expected_results = self.ty.results();
if params.len() != expected_params.len() {
return Err(Error::ArityMismatch {
expected: expected_params.len(),
provided: params.len(),
});
}
if results.len() < expected_results.len() {
return Err(Error::ArityMismatch {
expected: expected_results.len(),
provided: results.len(),
});
}
for (index, (param, &expected)) in params.iter().zip(expected_params).enumerate() {
if param.ty() != expected {
return Err(Error::TypeMismatch {
index,
expected: expected.name(),
found: param.ty().name(),
});
}
}
let args: Vec<sys::FizzyValue> = params.iter().map(|value| value.to_sys()).collect();
let args_ptr = if args.is_empty() {
core::ptr::null()
} else {
args.as_ptr()
};
let result = unsafe {
sys::fizzy_execute(
instance.as_ptr(),
self.func_idx,
args_ptr,
core::ptr::null_mut(),
)
};
if result.trapped {
return Err(Error::Trap);
}
if let Some(&result_ty) = expected_results.first() {
results[0] = Val::from_sys(result.value, result_ty);
}
Ok(())
}
}