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, ptr, str};
11use wasmi::{Error, Extern, Func, Nullable, Val};
12
13#[cfg(feature = "std")]
14use core::panic::AssertUnwindSafe;
15
16#[derive(Clone)]
20#[repr(transparent)]
21pub struct wasm_func_t {
22 inner: wasm_extern_t,
23}
24
25wasmi_c_api_macros::declare_ref!(wasm_func_t);
26
27pub type wasm_func_callback_t = extern "C" fn(
29 params: *const wasm_val_vec_t,
30 results: *mut wasm_val_vec_t,
31) -> Option<Box<wasm_trap_t>>;
32
33pub type wasm_func_callback_with_env_t = extern "C" fn(
35 env: *mut c_void,
36 params: *const wasm_val_vec_t,
37 results: *mut wasm_val_vec_t,
38) -> Option<Box<wasm_trap_t>>;
39
40impl wasm_func_t {
41 pub(crate) fn try_from(e: &wasm_extern_t) -> Option<&wasm_func_t> {
42 match &e.which {
43 Extern::Func(_) => Some(unsafe { &*(e as *const _ as *const _) }),
44 _ => None,
45 }
46 }
47
48 pub(crate) fn try_from_mut(e: &mut wasm_extern_t) -> Option<&mut wasm_func_t> {
49 match &mut e.which {
50 Extern::Func(_) => Some(unsafe { &mut *(e as *mut _ as *mut _) }),
51 _ => None,
52 }
53 }
54
55 pub(crate) fn func(&self) -> Func {
57 match self.inner.which {
58 Extern::Func(f) => f,
59 _ => unsafe { hint::unreachable_unchecked() },
60 }
61 }
62}
63
64unsafe fn create_function(
76 store: &mut wasm_store_t,
77 ty: &wasm_functype_t,
78 func: impl Fn(*const wasm_val_vec_t, *mut wasm_val_vec_t) -> Option<Box<wasm_trap_t>>
79 + Send
80 + Sync
81 + 'static,
82) -> Box<wasm_func_t> {
83 unsafe {
84 let ty = ty.ty().ty.clone();
85 let func = Func::new(
86 store.inner.context_mut(),
87 ty,
88 move |_caller, params, results| {
89 let params: wasm_val_vec_t = params
90 .iter()
91 .cloned()
92 .map(wasm_val_t::from)
93 .collect::<Box<[_]>>()
94 .into();
95 let mut out_results: wasm_val_vec_t =
96 vec![wasm_val_t::default(); results.len()].into();
97 if let Some(trap) = func(¶ms, &mut out_results) {
98 return Err(trap.error);
99 }
100 results
101 .iter_mut()
102 .zip(out_results.as_slice())
103 .for_each(|(result, out_results)| {
104 *result = out_results.to_val();
105 });
106 Ok(())
107 },
108 );
109 Box::new(wasm_func_t {
110 inner: wasm_extern_t {
111 store: store.inner.clone(),
112 which: func.into(),
113 },
114 })
115 }
116}
117
118#[cfg_attr(not(feature = "prefix-symbols"), unsafe(no_mangle))]
129#[cfg_attr(feature = "prefix-symbols", wasmi_c_api_macros::prefix_symbol)]
130pub unsafe extern "C" fn wasm_func_new(
131 store: &mut wasm_store_t,
132 ty: &wasm_functype_t,
133 callback: wasm_func_callback_t,
134) -> Box<wasm_func_t> {
135 unsafe { create_function(store, ty, move |params, results| callback(params, results)) }
136}
137
138#[cfg_attr(not(feature = "prefix-symbols"), unsafe(no_mangle))]
150#[cfg_attr(feature = "prefix-symbols", wasmi_c_api_macros::prefix_symbol)]
151pub unsafe extern "C" fn wasm_func_new_with_env(
152 store: &mut wasm_store_t,
153 ty: &wasm_functype_t,
154 callback: wasm_func_callback_with_env_t,
155 data: *mut c_void,
156 finalizer: Option<extern "C" fn(arg1: *mut c_void)>,
157) -> Box<wasm_func_t> {
158 unsafe {
159 let finalizer = crate::ForeignData { data, finalizer };
160 create_function(store, ty, move |params, results| {
161 let _ = &finalizer; callback(finalizer.data, params, results)
163 })
164 }
165}
166
167fn prepare_params_and_results(
171 dst: &mut Vec<Val>,
172 params: impl ExactSizeIterator<Item = Val>,
173 len_results: usize,
174) -> (&[Val], &mut [Val]) {
175 debug_assert!(dst.is_empty());
176 let len_params = params.len();
177 dst.reserve(len_params + len_results);
178 dst.extend(params);
179 dst.extend(iter::repeat_n(
180 Val::FuncRef(<Nullable<Func>>::Null),
181 len_results,
182 ));
183 let (params, results) = dst.split_at_mut(len_params);
184 (params, results)
185}
186
187#[cfg_attr(not(feature = "prefix-symbols"), unsafe(no_mangle))]
199#[cfg_attr(feature = "prefix-symbols", wasmi_c_api_macros::prefix_symbol)]
200pub unsafe extern "C" fn wasm_func_call(
201 func: &mut wasm_func_t,
202 params: *const wasm_val_vec_t,
203 results: *mut wasm_val_vec_t,
204) -> *mut wasm_trap_t {
205 unsafe {
206 let f = func.func();
207 let results = (*results).as_uninit_slice();
208 let params = (*params).as_slice();
209 let mut dst = Vec::new();
210 let (wt_params, wt_results) =
211 prepare_params_and_results(&mut dst, params.iter().map(|i| i.to_val()), results.len());
212
213 let result = {
214 #[cfg(feature = "std")]
215 {
216 std::panic::catch_unwind(AssertUnwindSafe(|| {
221 f.call(func.inner.store.context_mut(), wt_params, wt_results)
222 }))
223 }
224 #[cfg(not(feature = "std"))]
225 {
226 Ok(f.call(func.inner.store.context_mut(), wt_params, wt_results))
227 }
228 };
229 match result {
230 Ok(Ok(())) => {
231 for (slot, val) in results.iter_mut().zip(wt_results.iter().cloned()) {
232 crate::initialize(slot, wasm_val_t::from(val));
233 }
234 ptr::null_mut()
235 }
236 Ok(Err(err)) => Box::into_raw(Box::new(wasm_trap_t::new(err))),
237 Err(panic) => {
238 let err = error_from_panic(panic);
239 let trap = Box::new(wasm_trap_t::new(err));
240 Box::into_raw(trap)
241 }
242 }
243 }
244}
245
246fn error_from_panic(panic: Box<dyn Any + Send>) -> Error {
248 if let Some(msg) = panic.downcast_ref::<String>() {
249 Error::new(msg.clone())
250 } else if let Some(msg) = panic.downcast_ref::<&'static str>() {
251 Error::new(*msg)
252 } else {
253 Error::new("panic happened on the Rust side")
254 }
255}
256
257#[cfg_attr(not(feature = "prefix-symbols"), unsafe(no_mangle))]
266#[cfg_attr(feature = "prefix-symbols", wasmi_c_api_macros::prefix_symbol)]
267pub unsafe extern "C" fn wasm_func_type(f: &wasm_func_t) -> Box<wasm_functype_t> {
268 unsafe { Box::new(wasm_functype_t::new(f.func().ty(f.inner.store.context()))) }
269}
270
271#[cfg_attr(not(feature = "prefix-symbols"), unsafe(no_mangle))]
282#[cfg_attr(feature = "prefix-symbols", wasmi_c_api_macros::prefix_symbol)]
283pub unsafe extern "C" fn wasm_func_param_arity(f: &wasm_func_t) -> usize {
284 unsafe { f.func().ty(f.inner.store.context()).params().len() }
285}
286
287#[cfg_attr(not(feature = "prefix-symbols"), unsafe(no_mangle))]
298#[cfg_attr(feature = "prefix-symbols", wasmi_c_api_macros::prefix_symbol)]
299pub unsafe extern "C" fn wasm_func_result_arity(f: &wasm_func_t) -> usize {
300 unsafe { f.func().ty(f.inner.store.context()).results().len() }
301}
302
303#[cfg_attr(not(feature = "prefix-symbols"), unsafe(no_mangle))]
305#[cfg_attr(feature = "prefix-symbols", wasmi_c_api_macros::prefix_symbol)]
306pub extern "C" fn wasm_func_as_extern(f: &mut wasm_func_t) -> &mut wasm_extern_t {
307 &mut f.inner
308}
309
310#[cfg_attr(not(feature = "prefix-symbols"), unsafe(no_mangle))]
312#[cfg_attr(feature = "prefix-symbols", wasmi_c_api_macros::prefix_symbol)]
313pub extern "C" fn wasm_func_as_extern_const(f: &wasm_func_t) -> &wasm_extern_t {
314 &f.inner
315}