1use crate::{
2 ffi, instance::module::InnerInstance, r#async::fiber::AsyncCx, CallingFrame, FuncType,
3 Function, Instance, WasmEdgeResult, WasmValue,
4};
5use std::{future::Future, os::raw::c_void};
6use wasmedge_types::error::CoreError;
7
8use super::module::AsyncInstance;
9
10pub type AsyncFn<'data, 'inst, 'frame, 'fut, Data>
11 = fn(
16 &'data mut Data,
17 &'inst mut AsyncInstance,
18 &'frame mut CallingFrame,
19 Vec<WasmValue>,
20) -> Box<dyn Future<Output = Result<Vec<WasmValue>, CoreError>> + Send + 'fut>;
21
22unsafe extern "C" fn wrap_async_fn<Data>(
23 key_ptr: *mut c_void,
24 data: *mut std::os::raw::c_void,
25 call_frame_ctx: *const ffi::WasmEdge_CallingFrameContext,
26 params: *const ffi::WasmEdge_Value,
27 param_len: u32,
28 returns: *mut ffi::WasmEdge_Value,
29 return_len: u32,
30) -> ffi::WasmEdge_Result {
31 let mut frame = CallingFrame::create(call_frame_ctx);
32 let inst_ctx = ffi::WasmEdge_CallingFrameGetModuleInstance(call_frame_ctx);
34 let mut inst = std::mem::ManuallyDrop::new(AsyncInstance(Instance {
35 inner: InnerInstance(inst_ctx as _),
36 }));
37 let data = &mut *(data as *mut Data);
38
39 let input = if params.is_null() || param_len == 0 {
41 vec![]
42 } else {
43 let raw_input = unsafe { std::slice::from_raw_parts(params, param_len as usize) };
44 raw_input.iter().map(|r| (*r).into()).collect::<Vec<_>>()
45 };
46
47 let return_len = return_len as usize;
49 let mut empty_return = [];
50 let raw_returns = if returns.is_null() || return_len == 0 {
51 &mut empty_return
52 } else {
53 unsafe { std::slice::from_raw_parts_mut(returns, return_len) }
54 };
55
56 let real_fn: AsyncFn<'_, '_, '_, '_, Data> = std::mem::transmute(key_ptr);
58
59 let async_cx = AsyncCx::new();
60 let mut future = std::pin::Pin::from(real_fn(data, &mut inst, &mut frame, input));
61 let result = match unsafe { async_cx.block_on(future.as_mut()) } {
63 Ok(Ok(ret)) => Ok(ret),
64 Ok(Err(err)) => Err(err),
65 Err(_err) => Err(CoreError::Common(
66 wasmedge_types::error::CoreCommonError::Interrupted,
67 )),
68 };
69
70 match result {
72 Ok(returns) => {
73 assert!(returns.len() == return_len, "[wasmedge-sys] check the number of returns of async host function. Expected: {}, actual: {}", return_len, returns.len());
74 for (idx, wasm_value) in returns.into_iter().enumerate() {
75 raw_returns[idx] = wasm_value.as_raw();
76 }
77 ffi::WasmEdge_Result { Code: 0 }
78 }
79 Err(err) => err.into(),
80 }
81}
82
83pub struct AsyncFunction(pub(crate) Function);
84
85impl AsyncFunction {
86 pub fn create_async_func<'data, 'inst, 'frame, 'fut, T: Send>(
103 ty: &FuncType,
104 real_fn: AsyncFn<'data, 'inst, 'frame, 'fut, T>,
105 data: *mut T,
106 cost: u64,
107 ) -> WasmEdgeResult<Self>
108 where
109 'data: 'fut,
110 'inst: 'fut,
111 'frame: 'fut,
112 {
113 let f = unsafe {
114 Function::create_with_custom_wrapper(
115 ty,
116 wrap_async_fn::<T>,
117 real_fn as _,
118 data as _,
119 cost,
120 )
121 }?;
122 Ok(Self(f))
123 }
124}
125
126impl AsRef<Function> for AsyncFunction {
127 fn as_ref(&self) -> &Function {
128 &self.0
129 }
130}
131
132impl AsMut<Function> for AsyncFunction {
133 fn as_mut(&mut self) -> &mut Function {
134 &mut self.0
135 }
136}
137
138#[cfg(test)]
139mod tests {
140 use super::*;
141 use crate::{
142 instance::function::AsFunc,
143 r#async::{fiber::AsyncState, module::AsyncImportObject},
144 types::WasmValue,
145 AsInstance, Executor,
146 };
147
148 use wasmedge_types::{error::CoreExecutionError, FuncType, ValType};
149
150 #[tokio::test]
151 async fn test_func_basic() {
152 #[derive(Debug)]
153 struct Data<T, S> {
154 _x: i32,
155 _y: String,
156 _v: Vec<T>,
157 _s: Vec<S>,
158 }
159
160 let data: Data<i32, &str> = Data {
161 _x: 12,
162 _y: "hello".to_string(),
163 _v: vec![1, 2, 3],
164 _s: vec!["macos", "linux", "windows"],
165 };
166
167 fn real_add<T: core::fmt::Debug>(
168 _host_data: &mut Data<i32, &str>,
169 _inst: &mut AsyncInstance,
170 _frame: &mut CallingFrame,
171 input: Vec<WasmValue>,
172 ) -> Box<dyn Future<Output = Result<Vec<WasmValue>, CoreError>> + Send> {
173 Box::new(async move {
174 println!("Rust: Entering Rust function real_add");
175
176 if input.len() != 2 {
177 return Err(CoreError::Execution(CoreExecutionError::FuncSigMismatch));
178 }
179
180 let a = if input[0].ty() == ValType::I32 {
181 input[0].to_i32()
182 } else {
183 return Err(CoreError::Execution(CoreExecutionError::FuncSigMismatch));
184 };
185
186 let b = if input[1].ty() == ValType::I32 {
187 input[1].to_i32()
188 } else {
189 return Err(CoreError::Execution(CoreExecutionError::FuncSigMismatch));
190 };
191
192 tokio::time::sleep(std::time::Duration::from_millis(300)).await;
193
194 let c = a + b;
195 println!("Rust: calcuating in real_add c: {c:?}");
196
197 println!("Rust: Leaving Rust function real_add");
198 Ok(vec![WasmValue::from_i32(c)])
199 })
200 }
201
202 let mut import_module = AsyncImportObject::create("test_module", Box::new(data)).unwrap();
203
204 let func_ty = FuncType::new(vec![ValType::I32; 2], vec![ValType::I32]);
206 let result = AsyncFunction::create_async_func(
208 &func_ty,
209 real_add::<Data<i32, &str>>,
210 import_module.get_host_data_mut(),
211 0,
212 );
213 assert!(result.is_ok());
214 let host_func = result.unwrap();
215
216 let result = host_func.ty();
218 assert!(result.is_some());
219 let ty = result.unwrap();
220
221 assert_eq!(ty.args_len(), 2);
223 assert_eq!(ty.args(), &[ValType::I32; 2]);
224
225 assert_eq!(ty.returns_len(), 1);
227 assert_eq!(ty.returns(), &[ValType::I32]);
228
229 import_module.add_async_func("add", host_func);
230
231 let result = Executor::create(None, None);
233 assert!(result.is_ok());
234 let mut executor = result.unwrap();
235
236 let mut add_func = import_module.get_func_mut("add").unwrap();
237
238 let async_state = AsyncState::new();
239
240 let result = executor
241 .call_func_async(
242 &async_state,
243 &mut add_func,
244 vec![WasmValue::from_i32(1), WasmValue::from_i32(2)],
245 )
246 .await;
247
248 assert!(result.is_ok());
249 let returns = result.unwrap();
250 assert_eq!(returns[0].to_i32(), 3);
251 }
252}