1 use wasmtime::{Engine, Linker, Module, Store, Val};
2 use wiggle::GuestMemory;
3 
4 wiggle::from_witx!({
5     witx: ["tests/atoms.witx"],
6     async: {
7         atoms::{double_int_return_float}
8     }
9 });
10 
11 pub struct Ctx;
12 impl wiggle::GuestErrorType for types::Errno {
success() -> Self13     fn success() -> Self {
14         types::Errno::Ok
15     }
16 }
17 
18 impl atoms::Atoms for Ctx {
int_float_args( &mut self, _: &mut GuestMemory<'_>, an_int: u32, an_float: f32, ) -> Result<(), types::Errno>19     fn int_float_args(
20         &mut self,
21         _: &mut GuestMemory<'_>,
22         an_int: u32,
23         an_float: f32,
24     ) -> Result<(), types::Errno> {
25         println!("INT FLOAT ARGS: {an_int} {an_float}");
26         Ok(())
27     }
double_int_return_float( &mut self, _: &mut GuestMemory<'_>, an_int: u32, ) -> Result<types::AliasToFloat, types::Errno>28     async fn double_int_return_float(
29         &mut self,
30         _: &mut GuestMemory<'_>,
31         an_int: u32,
32     ) -> Result<types::AliasToFloat, types::Errno> {
33         // Do something inside this test that is Pending for a trivial amount of time,
34         // to make sure we are hooked up to the tokio executor properly.
35         tokio::time::sleep(tokio::time::Duration::from_millis(10)).await;
36         Ok((an_int as f32) * 2.0)
37     }
38 }
39 
40 #[tokio::test]
test_sync_host_func()41 async fn test_sync_host_func() {
42     let mut store = async_store();
43     let mut linker = Linker::<Ctx>::new(store.engine());
44     atoms::add_to_linker(&mut linker, |cx| cx).unwrap();
45     let shim_mod = shim_module(linker.engine());
46     let shim_inst = linker
47         .instantiate_async(&mut store, &shim_mod)
48         .await
49         .unwrap();
50 
51     let mut results = [Val::I32(0)];
52     shim_inst
53         .get_func(&mut store, "int_float_args_shim")
54         .unwrap()
55         .call_async(&mut store, &[0i32.into(), 123.45f32.into()], &mut results)
56         .await
57         .unwrap();
58 
59     assert_eq!(
60         results[0].unwrap_i32(),
61         types::Errno::Ok as i32,
62         "int_float_args errno"
63     );
64 }
65 
66 #[tokio::test]
test_async_host_func()67 async fn test_async_host_func() {
68     let mut store = async_store();
69     let mut linker = Linker::<Ctx>::new(store.engine());
70     atoms::add_to_linker(&mut linker, |cx| cx).unwrap();
71 
72     let shim_mod = shim_module(linker.engine());
73     let shim_inst = linker
74         .instantiate_async(&mut store, &shim_mod)
75         .await
76         .unwrap();
77 
78     let input: i32 = 123;
79     let result_location: i32 = 0;
80 
81     let mut results = [Val::I32(0)];
82     shim_inst
83         .get_func(&mut store, "double_int_return_float_shim")
84         .unwrap()
85         .call_async(
86             &mut store,
87             &[input.into(), result_location.into()],
88             &mut results,
89         )
90         .await
91         .unwrap();
92 
93     assert_eq!(
94         results[0].unwrap_i32(),
95         types::Errno::Ok as i32,
96         "double_int_return_float errno"
97     );
98 
99     // The actual result is in memory:
100     let mem = shim_inst.get_memory(&mut store, "memory").unwrap();
101     let mut result_bytes: [u8; 4] = [0, 0, 0, 0];
102     mem.read(&store, result_location as usize, &mut result_bytes)
103         .unwrap();
104     let result = f32::from_le_bytes(result_bytes);
105     assert_eq!((input * 2) as f32, result);
106 }
107 
async_store() -> Store<Ctx>108 fn async_store() -> Store<Ctx> {
109     Store::new(&Engine::default(), Ctx)
110 }
111 
112 // Wiggle expects the caller to have an exported memory. Wasmtime can only
113 // provide this if the caller is a WebAssembly module, so we need to write
114 // a shim module:
shim_module(engine: &Engine) -> Module115 fn shim_module(engine: &Engine) -> Module {
116     Module::new(
117         engine,
118         r#"
119         (module
120             (import "atoms" "int_float_args" (func $int_float_args (param i32 f32) (result i32)))
121             (import "atoms" "double_int_return_float" (func $double_int_return_float (param i32 i32) (result i32)))
122 
123             (memory 1)
124             (export "memory" (memory 0))
125 
126             (func $int_float_args_shim (param i32 f32) (result i32)
127                 local.get 0
128                 local.get 1
129                 call $int_float_args
130             )
131             (func $double_int_return_float_shim (param i32 i32) (result i32)
132                 local.get 0
133                 local.get 1
134                 call $double_int_return_float
135             )
136             (export "int_float_args_shim" (func $int_float_args_shim))
137             (export "double_int_return_float_shim" (func $double_int_return_float_shim))
138         )
139         "#,
140     )
141     .unwrap()
142 }
143