Skip to main content

wasmedge_sys/instance/
function.rs

1//! Defines WasmEdge Function and FuncType structs.
2
3use crate::{
4    ffi::{self},
5    CallingFrame, Instance, WasmEdgeResult, WasmValue,
6};
7use core::ffi::c_void;
8
9use wasmedge_types::{
10    error::{CoreError, FuncError, WasmEdgeError},
11    ValType,
12};
13
14use super::{module::InnerInstance, InnerRef};
15
16pub type SyncFn<Data> = for<'a, 'b, 'c> fn(
17    &'a mut Data,
18    &'b mut Instance,
19    &'c mut CallingFrame,
20    Vec<WasmValue>,
21) -> Result<Vec<WasmValue>, CoreError>;
22
23pub type CustomFnWrapper = unsafe extern "C" fn(
24    key_ptr: *mut c_void,
25    data_ptr: *mut c_void,
26    calling_frame_ctx: *const ffi::WasmEdge_CallingFrameContext,
27    params: *const ffi::WasmEdge_Value,
28    param_len: u32,
29    returns: *mut ffi::WasmEdge_Value,
30    return_len: u32,
31) -> ffi::WasmEdge_Result;
32
33// Wrapper function for thread-safe scenarios.
34unsafe extern "C" fn wrap_fn<Data>(
35    key_ptr: *mut c_void,
36    data: *mut std::os::raw::c_void,
37    call_frame_ctx: *const ffi::WasmEdge_CallingFrameContext,
38    params: *const ffi::WasmEdge_Value,
39    param_len: u32,
40    returns: *mut ffi::WasmEdge_Value,
41    return_len: u32,
42) -> ffi::WasmEdge_Result {
43    let mut frame = CallingFrame::create(call_frame_ctx);
44    // let executor_ctx = ffi::WasmEdge_CallingFrameGetExecutor(call_frame_ctx);
45    let inst_ctx = ffi::WasmEdge_CallingFrameGetModuleInstance(call_frame_ctx);
46    let mut inst = std::mem::ManuallyDrop::new(Instance {
47        inner: InnerInstance(inst_ctx as _),
48    });
49    let data = &mut *(data as *mut Data);
50
51    let input = if params.is_null() || param_len == 0 {
52        vec![]
53    } else {
54        let raw_input = unsafe { std::slice::from_raw_parts(params, param_len as usize) };
55        raw_input.iter().map(|r| (*r).into()).collect::<Vec<_>>()
56    };
57
58    let return_len = return_len as usize;
59
60    let mut empty_return = [];
61    let raw_returns = if returns.is_null() || return_len == 0 {
62        &mut empty_return
63    } else {
64        unsafe { std::slice::from_raw_parts_mut(returns, return_len) }
65    };
66
67    let real_fn: SyncFn<Data> = std::mem::transmute(key_ptr);
68
69    match real_fn(data, &mut inst, &mut frame, input) {
70        Ok(returns) => {
71            assert!(returns.len() == return_len, "[wasmedge-sys] check the number of returns of host function. Expected: {}, actual: {}", return_len, returns.len());
72            for (idx, wasm_value) in returns.into_iter().enumerate() {
73                raw_returns[idx] = wasm_value.as_raw();
74            }
75            ffi::WasmEdge_Result { Code: 0 }
76        }
77
78        Err(err) => err.into(),
79    }
80}
81
82/// Defines a host function.
83///
84/// A WasmEdge [Function] defines a WebAssembly host function described by its [type](crate::FuncType). A host function is a closure of the original function defined in either the host or the WebAssembly module.
85#[derive(Debug)]
86pub struct Function {
87    pub(crate) inner: InnerFunc,
88}
89impl Function {
90    /// Creates a [host function](crate::Function) with the given function type.
91    ///
92    /// N.B. that this function is used for thread-safe scenarios.
93    ///
94    /// # Arguments
95    ///
96    /// * `ty` - The types of the arguments and returns of the target function.
97    ///
98    /// * `real_fn` - The pointer to the target function.
99    ///
100    /// * `data` - The host context data used in this function.
101    ///
102    /// * `cost` - The function cost in the [Statistics](crate::Statistics). Pass 0 if the calculation is not needed.
103    ///
104    /// # Error
105    ///
106    /// * If fail to create a [Function], then [WasmEdgeError::Func(FuncError::Create)](wasmedge_types::error::FuncError) is returned.
107    ///
108    /// # Safety
109    ///
110    /// The lifetime of `data` must be greater than that of `Function` itself.
111    pub unsafe fn create_sync_func<T>(
112        ty: &wasmedge_types::FuncType,
113        real_fn: SyncFn<T>,
114        data: *mut T,
115        cost: u64,
116    ) -> WasmEdgeResult<Self> {
117        unsafe { Self::create_with_data(ty, real_fn, data, cost) }
118    }
119
120    /// Creates a [host function](crate::Function) with the given function type.
121    ///
122    /// N.B. that this function is used for thread-safe scenarios.
123    ///
124    /// # Arguments
125    ///
126    /// * `ty` - The types of the arguments and returns of the target function.
127    ///
128    /// * `real_fn` - The pointer to the target function.
129    ///
130    /// * `data` - The pointer to the host context data used in this function.
131    ///
132    /// * `cost` - The function cost in the [Statistics](crate::Statistics). Pass 0 if the calculation is not needed.
133    ///
134    /// # Error
135    ///
136    /// * If fail to create a [Function], then [WasmEdgeError::Func(FuncError::Create)](crate::error::FuncError) is returned.
137    ///
138    unsafe fn create_with_data<T>(
139        ty: &wasmedge_types::FuncType,
140        real_fn: SyncFn<T>,
141        data: *mut T,
142        cost: u64,
143    ) -> WasmEdgeResult<Self> {
144        Self::create_with_custom_wrapper(ty, wrap_fn::<T>, real_fn as _, data as _, cost)
145    }
146
147    /// Creates a [host function](crate::Function) with the given function type and the custom function wrapper.
148    ///
149    /// # Arguments
150    ///
151    /// * `ty` - The types of the arguments and returns of the target function.
152    ///
153    /// * `fn_wrapper` - The custom function wrapper.
154    ///
155    /// * `real_fn` - The pointer to the target function.
156    ///
157    /// * `data` - The pointer to the host context data used in this function.
158    ///
159    /// * `cost` - The function cost in the [Statistics](crate::Statistics). Pass 0 if the calculation is not needed.
160    ///
161    /// # Error
162    ///
163    /// * If fail to create a [Function], then [WasmEdgeError::Func(FuncError::Create)](wasmedge_types::error::FuncError) is returned.
164    ///
165    /// # Safety
166    ///
167    /// Notice that the caller should guarantee the life cycle of both the `real_fn` and the `data` object.
168    ///
169    pub unsafe fn create_with_custom_wrapper(
170        ty: &wasmedge_types::FuncType,
171        fn_wrapper: CustomFnWrapper,
172        real_fn: *mut c_void,
173        data: *mut c_void,
174        cost: u64,
175    ) -> WasmEdgeResult<Self> {
176        let ty: FuncTypeOwn = ty.into();
177        let ctx = ffi::WasmEdge_FunctionInstanceCreateBinding(
178            ty.inner.0,
179            Some(fn_wrapper),
180            real_fn,
181            data,
182            cost,
183        );
184
185        if ctx.is_null() {
186            Err(Box::new(WasmEdgeError::Func(FuncError::Create)))
187        } else {
188            Ok(Self {
189                inner: InnerFunc(ctx),
190            })
191        }
192    }
193
194    /// # Safety
195    ///
196    /// The lifetime of the returned pointer must not exceed that of the object itself.
197    pub unsafe fn as_ptr(&self) -> *mut ffi::WasmEdge_FunctionInstanceContext {
198        self.inner.0
199    }
200
201    /// # Safety
202    ///
203    /// This function will take over the lifetime management of `ctx`, so do not call `ffi::WasmEdge_FunctionInstanceDelete` on `ctx` after this.
204    pub unsafe fn from_raw(ctx: *mut ffi::WasmEdge_FunctionInstanceContext) -> Self {
205        Self {
206            inner: InnerFunc(ctx),
207        }
208    }
209}
210impl Drop for Function {
211    fn drop(&mut self) {
212        unsafe { ffi::WasmEdge_FunctionInstanceDelete(self.inner.0) };
213    }
214}
215
216/// Defines a reference to a [host function](crate::Function).
217pub type FuncRef<Ref> = InnerRef<Function, Ref>;
218
219pub trait AsFunc {
220    /// # Safety
221    ///
222    /// The lifetime of the returned pointer must not exceed that of the object itself.
223    unsafe fn get_func_raw(&self) -> *mut ffi::WasmEdge_FunctionInstanceContext;
224
225    fn ty(&self) -> Option<wasmedge_types::FuncType>
226    where
227        Self: Sized,
228    {
229        let ty = unsafe { ffi::WasmEdge_FunctionInstanceGetFunctionType(self.get_func_raw()) };
230        if ty.is_null() {
231            None
232        } else {
233            let value = std::mem::ManuallyDrop::new(FuncTypeOwn {
234                inner: InnerFuncType(ty),
235            });
236            Some((&*value).into())
237        }
238    }
239}
240
241impl AsFunc for Function {
242    unsafe fn get_func_raw(&self) -> *mut ffi::WasmEdge_FunctionInstanceContext {
243        self.inner.0
244    }
245}
246impl<F: AsRef<Function>> AsFunc for F {
247    unsafe fn get_func_raw(&self) -> *mut ffi::WasmEdge_FunctionInstanceContext {
248        self.as_ref().get_func_raw()
249    }
250}
251
252#[derive(Debug, Clone, Copy)]
253pub(crate) struct InnerFunc(pub(crate) *mut ffi::WasmEdge_FunctionInstanceContext);
254unsafe impl Send for InnerFunc {}
255unsafe impl Sync for InnerFunc {}
256
257#[derive(Debug)]
258pub(crate) struct FuncTypeOwn {
259    pub(crate) inner: InnerFuncType,
260}
261impl FuncTypeOwn {
262    /// Create a new [FuncType] to be associated with the given arguments and returns.
263    ///
264    /// # Arguments
265    ///
266    /// * `args` - The argument types of a [Function].
267    ///
268    /// * `returns` - The types of the returns of a [Function].
269    ///
270    /// # Error
271    ///
272    /// If fail to create a [FuncType], then an error is returned.
273    pub(crate) fn create<I: IntoIterator<Item = ValType>, R: IntoIterator<Item = ValType>>(
274        args: I,
275        returns: R,
276    ) -> WasmEdgeResult<Self> {
277        let param_tys = args
278            .into_iter()
279            .map(|x| x.into())
280            .collect::<Vec<ffi::WasmEdge_ValType>>();
281        let ret_tys = returns
282            .into_iter()
283            .map(|x| x.into())
284            .collect::<Vec<ffi::WasmEdge_ValType>>();
285
286        let ctx = unsafe {
287            ffi::WasmEdge_FunctionTypeCreate(
288                param_tys.as_ptr() as *const _,
289                param_tys.len() as u32,
290                ret_tys.as_ptr() as *const _,
291                ret_tys.len() as u32,
292            )
293        };
294        match ctx.is_null() {
295            true => Err(Box::new(WasmEdgeError::FuncTypeCreate)),
296            false => Ok(Self {
297                inner: InnerFuncType(ctx),
298            }),
299        }
300    }
301}
302impl Drop for FuncTypeOwn {
303    fn drop(&mut self) {
304        unsafe { ffi::WasmEdge_FunctionTypeDelete(self.inner.0 as _) }
305    }
306}
307
308impl FuncTypeOwn {
309    /// Returns the number of the arguments of a [Function].
310    pub(crate) fn params_len(&self) -> u32 {
311        unsafe { ffi::WasmEdge_FunctionTypeGetParametersLength(self.inner.0) }
312    }
313
314    /// Returns an Iterator of the arguments of a [Function].
315    pub(crate) fn params_type_iter(&self) -> impl Iterator<Item = ValType> {
316        let len = self.params_len();
317        let mut types = Vec::with_capacity(len as usize);
318        unsafe {
319            ffi::WasmEdge_FunctionTypeGetParameters(self.inner.0, types.as_mut_ptr(), len);
320            types.set_len(len as usize);
321        }
322
323        types.into_iter().map(Into::into)
324    }
325
326    ///Returns the number of the returns of a [Function].
327    pub(crate) fn returns_len(&self) -> u32 {
328        unsafe { ffi::WasmEdge_FunctionTypeGetReturnsLength(self.inner.0) }
329    }
330
331    /// Returns an Iterator of the return types of a [Function].
332    pub(crate) fn returns_type_iter(&self) -> impl Iterator<Item = ValType> {
333        let len = self.returns_len();
334        let mut types = Vec::with_capacity(len as usize);
335        unsafe {
336            ffi::WasmEdge_FunctionTypeGetReturns(self.inner.0, types.as_mut_ptr(), len);
337            types.set_len(len as usize);
338        }
339
340        types.into_iter().map(Into::into)
341    }
342}
343
344impl From<&wasmedge_types::FuncType> for FuncTypeOwn {
345    fn from(ty: &wasmedge_types::FuncType) -> Self {
346        FuncTypeOwn::create(ty.args().to_vec(), ty.returns().to_vec()).expect("[wasmedge-sys] Failed to convert wasmedge_types::FuncType into wasmedge_sys::FuncType.")
347    }
348}
349
350impl From<wasmedge_types::FuncType> for FuncTypeOwn {
351    fn from(ty: wasmedge_types::FuncType) -> Self {
352        (&ty).into()
353    }
354}
355
356impl From<&FuncTypeOwn> for wasmedge_types::FuncType {
357    fn from(ty: &FuncTypeOwn) -> Self {
358        let args = ty.params_type_iter().collect();
359        let returns = ty.returns_type_iter().collect();
360
361        wasmedge_types::FuncType::new(args, returns)
362    }
363}
364
365#[derive(Debug)]
366pub(crate) struct InnerFuncType(pub(crate) *const ffi::WasmEdge_FunctionTypeContext);
367unsafe impl Send for InnerFuncType {}
368unsafe impl Sync for InnerFuncType {}
369
370#[cfg(test)]
371mod tests {
372    use super::*;
373    use crate::{types::WasmValue, AsInstance, Executor, ImportModule};
374
375    use wasmedge_types::{error::CoreExecutionError, FuncType, ValType};
376
377    #[test]
378    fn test_func_type() {
379        // test FuncType with args and returns
380        {
381            let param_tys = vec![
382                ValType::I32,
383                ValType::I64,
384                ValType::F32,
385                ValType::F64,
386                ValType::V128,
387                ValType::ExternRef,
388            ];
389            let param_len = param_tys.len();
390            let ret_tys = vec![ValType::FuncRef, ValType::ExternRef, ValType::V128];
391            let ret_len = ret_tys.len();
392
393            // create FuncType
394            let result = FuncTypeOwn::create(param_tys, ret_tys);
395            assert!(result.is_ok());
396            let func_ty = result.unwrap();
397
398            // check parameters
399            assert_eq!(func_ty.params_len(), param_len as u32);
400            let param_tys = func_ty.params_type_iter().collect::<Vec<_>>();
401            assert_eq!(
402                param_tys,
403                vec![
404                    ValType::I32,
405                    ValType::I64,
406                    ValType::F32,
407                    ValType::F64,
408                    ValType::V128,
409                    ValType::ExternRef,
410                ]
411            );
412
413            // check returns
414            assert_eq!(func_ty.returns_len(), ret_len as u32);
415            let return_tys = func_ty.returns_type_iter().collect::<Vec<_>>();
416            assert_eq!(
417                return_tys,
418                vec![ValType::FuncRef, ValType::ExternRef, ValType::V128]
419            );
420        }
421
422        // test FuncType without args and returns
423        {
424            // create FuncType
425            let result = FuncTypeOwn::create([], []);
426            assert!(result.is_ok());
427            let func_ty = result.unwrap();
428
429            assert_eq!(func_ty.params_len(), 0);
430            assert_eq!(func_ty.returns_len(), 0);
431        }
432    }
433
434    #[test]
435    fn test_func_basic() {
436        #[derive(Debug)]
437        struct Data<T, S> {
438            _x: i32,
439            _y: String,
440            _v: Vec<T>,
441            _s: Vec<S>,
442        }
443
444        let data: Data<i32, &str> = Data {
445            _x: 12,
446            _y: "hello".to_string(),
447            _v: vec![1, 2, 3],
448            _s: vec!["macos", "linux", "windows"],
449        };
450
451        fn real_add<T: core::fmt::Debug>(
452            _host_data: &mut Data<i32, &str>,
453            _inst: &mut Instance,
454            _frame: &mut CallingFrame,
455            input: Vec<WasmValue>,
456        ) -> Result<Vec<WasmValue>, CoreError> {
457            println!("Rust: Entering Rust function real_add");
458
459            if input.len() != 2 {
460                return Err(CoreError::Execution(CoreExecutionError::FuncSigMismatch));
461            }
462
463            let a = if input[0].ty() == ValType::I32 {
464                input[0].to_i32()
465            } else {
466                return Err(CoreError::Execution(CoreExecutionError::FuncSigMismatch));
467            };
468
469            let b = if input[1].ty() == ValType::I32 {
470                input[1].to_i32()
471            } else {
472                return Err(CoreError::Execution(CoreExecutionError::FuncSigMismatch));
473            };
474
475            let c = a + b;
476            println!("Rust: calcuating in real_add c: {c:?}");
477
478            println!("Rust: Leaving Rust function real_add");
479            Ok(vec![WasmValue::from_i32(c)])
480        }
481
482        let mut import_module = ImportModule::create("test_module", Box::new(data)).unwrap();
483
484        // create a FuncType
485        let func_ty = FuncType::new(vec![ValType::I32; 2], vec![ValType::I32]);
486        // create a host function
487        let result = unsafe {
488            Function::create_sync_func(
489                &func_ty,
490                real_add::<Data<i32, &str>>,
491                import_module.get_host_data_mut(),
492                0,
493            )
494        };
495        assert!(result.is_ok());
496        let host_func = result.unwrap();
497
498        // get func type
499        let result = host_func.ty();
500        assert!(result.is_some());
501        let ty = result.unwrap();
502
503        // check parameters
504        assert_eq!(ty.args_len(), 2);
505        assert_eq!(ty.args(), &[ValType::I32; 2]);
506
507        // check returns
508        assert_eq!(ty.returns_len(), 1);
509        assert_eq!(ty.returns(), &[ValType::I32]);
510
511        import_module.add_func("add", host_func);
512
513        // run this function
514        let result = Executor::create(None, None);
515        assert!(result.is_ok());
516        let mut executor = result.unwrap();
517
518        let mut add_func = import_module.get_func_mut("add").unwrap();
519
520        let result = executor.call_func(
521            &mut add_func,
522            vec![WasmValue::from_i32(1), WasmValue::from_i32(2)],
523        );
524
525        assert!(result.is_ok());
526        let returns = result.unwrap();
527        assert_eq!(returns[0].to_i32(), 3);
528    }
529}