1use crate::{
2 wasm_extern_t,
3 wasm_functype_t,
4 wasm_store_t,
5 wasm_trap_t,
6 wasm_val_t,
7 wasm_val_vec_t,
8};
9use alloc::{boxed::Box, string::String, vec, vec::Vec};
10use core::{any::Any, ffi::c_void, hint, iter, panic::AssertUnwindSafe, ptr, str};
11use wasmi::{Error, Extern, Func, FuncRef, Val};
12
13#[derive(Clone)]
17#[repr(transparent)]
18pub struct wasm_func_t {
19 inner: wasm_extern_t,
20}
21
22wasmi_c_api_macros::declare_ref!(wasm_func_t);
23
24pub type wasm_func_callback_t = extern "C" fn(
26 params: *const wasm_val_vec_t,
27 results: *mut wasm_val_vec_t,
28) -> Option<Box<wasm_trap_t>>;
29
30pub type wasm_func_callback_with_env_t = extern "C" fn(
32 env: *mut c_void,
33 params: *const wasm_val_vec_t,
34 results: *mut wasm_val_vec_t,
35) -> Option<Box<wasm_trap_t>>;
36
37impl wasm_func_t {
38 pub(crate) fn try_from(e: &wasm_extern_t) -> Option<&wasm_func_t> {
39 match &e.which {
40 Extern::Func(_) => Some(unsafe { &*(e as *const _ as *const _) }),
41 _ => None,
42 }
43 }
44
45 pub(crate) fn try_from_mut(e: &mut wasm_extern_t) -> Option<&mut wasm_func_t> {
46 match &mut e.which {
47 Extern::Func(_) => Some(unsafe { &mut *(e as *mut _ as *mut _) }),
48 _ => None,
49 }
50 }
51
52 pub(crate) fn func(&self) -> Func {
54 match self.inner.which {
55 Extern::Func(f) => f,
56 _ => unsafe { hint::unreachable_unchecked() },
57 }
58 }
59}
60
61unsafe fn create_function(
73 store: &mut wasm_store_t,
74 ty: &wasm_functype_t,
75 func: impl Fn(*const wasm_val_vec_t, *mut wasm_val_vec_t) -> Option<Box<wasm_trap_t>>
76 + Send
77 + Sync
78 + 'static,
79) -> Box<wasm_func_t> {
80 let ty = ty.ty().ty.clone();
81 let func = Func::new(
82 store.inner.context_mut(),
83 ty,
84 move |_caller, params, results| {
85 let params: wasm_val_vec_t = params
86 .iter()
87 .cloned()
88 .map(wasm_val_t::from)
89 .collect::<Box<[_]>>()
90 .into();
91 let mut out_results: wasm_val_vec_t = vec![wasm_val_t::default(); results.len()].into();
92 if let Some(trap) = func(¶ms, &mut out_results) {
93 return Err(trap.error);
94 }
95 results
96 .iter_mut()
97 .zip(out_results.as_slice())
98 .for_each(|(result, out_results)| {
99 *result = out_results.to_val();
100 });
101 Ok(())
102 },
103 );
104 Box::new(wasm_func_t {
105 inner: wasm_extern_t {
106 store: store.inner.clone(),
107 which: func.into(),
108 },
109 })
110}
111
112#[cfg_attr(not(feature = "prefix-symbols"), no_mangle)]
123#[cfg_attr(feature = "prefix-symbols", wasmi_c_api_macros::prefix_symbol)]
124pub unsafe extern "C" fn wasm_func_new(
125 store: &mut wasm_store_t,
126 ty: &wasm_functype_t,
127 callback: wasm_func_callback_t,
128) -> Box<wasm_func_t> {
129 #[allow(clippy::redundant_closure)] create_function(store, ty, move |params, results| callback(params, results))
131}
132
133#[cfg_attr(not(feature = "prefix-symbols"), no_mangle)]
145#[cfg_attr(feature = "prefix-symbols", wasmi_c_api_macros::prefix_symbol)]
146pub unsafe extern "C" fn wasm_func_new_with_env(
147 store: &mut wasm_store_t,
148 ty: &wasm_functype_t,
149 callback: wasm_func_callback_with_env_t,
150 data: *mut c_void,
151 finalizer: Option<extern "C" fn(arg1: *mut c_void)>,
152) -> Box<wasm_func_t> {
153 let finalizer = crate::ForeignData { data, finalizer };
154 create_function(store, ty, move |params, results| {
155 let _ = &finalizer; callback(finalizer.data, params, results)
157 })
158}
159
160fn prepare_params_and_results(
164 dst: &mut Vec<Val>,
165 params: impl ExactSizeIterator<Item = Val>,
166 len_results: usize,
167) -> (&[Val], &mut [Val]) {
168 debug_assert!(dst.is_empty());
169 let len_params = params.len();
170 dst.reserve(len_params + len_results);
171 dst.extend(params);
172 dst.extend(iter::repeat_n(Val::FuncRef(FuncRef::null()), len_results));
173 let (params, results) = dst.split_at_mut(len_params);
174 (params, results)
175}
176
177#[cfg_attr(not(feature = "prefix-symbols"), no_mangle)]
189#[cfg_attr(feature = "prefix-symbols", wasmi_c_api_macros::prefix_symbol)]
190pub unsafe extern "C" fn wasm_func_call(
191 func: &mut wasm_func_t,
192 params: *const wasm_val_vec_t,
193 results: *mut wasm_val_vec_t,
194) -> *mut wasm_trap_t {
195 let f = func.func();
196 let results = (*results).as_uninit_slice();
197 let params = (*params).as_slice();
198 let mut dst = Vec::new();
199 let (wt_params, wt_results) =
200 prepare_params_and_results(&mut dst, params.iter().map(|i| i.to_val()), results.len());
201
202 let result = {
203 #[cfg(feature = "std")]
204 {
205 std::panic::catch_unwind(AssertUnwindSafe(|| {
210 f.call(func.inner.store.context_mut(), wt_params, wt_results)
211 }))
212 }
213 #[cfg(not(feature = "std"))]
214 {
215 Ok(f.call(func.inner.store.context_mut(), wt_params, wt_results))
216 }
217 };
218 match result {
219 Ok(Ok(())) => {
220 for (slot, val) in results.iter_mut().zip(wt_results.iter().cloned()) {
221 crate::initialize(slot, wasm_val_t::from(val));
222 }
223 ptr::null_mut()
224 }
225 Ok(Err(err)) => Box::into_raw(Box::new(wasm_trap_t::new(err))),
226 Err(panic) => {
227 let err = error_from_panic(panic);
228 let trap = Box::new(wasm_trap_t::new(err));
229 Box::into_raw(trap)
230 }
231 }
232}
233
234fn error_from_panic(panic: Box<dyn Any + Send>) -> Error {
236 if let Some(msg) = panic.downcast_ref::<String>() {
237 Error::new(msg.clone())
238 } else if let Some(msg) = panic.downcast_ref::<&'static str>() {
239 Error::new(*msg)
240 } else {
241 Error::new("panic happened on the Rust side")
242 }
243}
244
245#[cfg_attr(not(feature = "prefix-symbols"), no_mangle)]
254#[cfg_attr(feature = "prefix-symbols", wasmi_c_api_macros::prefix_symbol)]
255pub unsafe extern "C" fn wasm_func_type(f: &wasm_func_t) -> Box<wasm_functype_t> {
256 Box::new(wasm_functype_t::new(f.func().ty(f.inner.store.context())))
257}
258
259#[cfg_attr(not(feature = "prefix-symbols"), no_mangle)]
270#[cfg_attr(feature = "prefix-symbols", wasmi_c_api_macros::prefix_symbol)]
271pub unsafe extern "C" fn wasm_func_param_arity(f: &wasm_func_t) -> usize {
272 f.func().ty(f.inner.store.context()).params().len()
273}
274
275#[cfg_attr(not(feature = "prefix-symbols"), no_mangle)]
286#[cfg_attr(feature = "prefix-symbols", wasmi_c_api_macros::prefix_symbol)]
287pub unsafe extern "C" fn wasm_func_result_arity(f: &wasm_func_t) -> usize {
288 f.func().ty(f.inner.store.context()).results().len()
289}
290
291#[cfg_attr(not(feature = "prefix-symbols"), no_mangle)]
293#[cfg_attr(feature = "prefix-symbols", wasmi_c_api_macros::prefix_symbol)]
294pub extern "C" fn wasm_func_as_extern(f: &mut wasm_func_t) -> &mut wasm_extern_t {
295 &mut f.inner
296}
297
298#[cfg_attr(not(feature = "prefix-symbols"), no_mangle)]
300#[cfg_attr(feature = "prefix-symbols", wasmi_c_api_macros::prefix_symbol)]
301pub extern "C" fn wasm_func_as_extern_const(f: &wasm_func_t) -> &wasm_extern_t {
302 &f.inner
303}