Skip to content
This repository was archived by the owner on Oct 3, 2025. It is now read-only.

Commit ff0c467

Browse files
committed
test: add example/test for async
on a side note: the hell am i seeing, did this just worked on the first try? what black magic is this? i guess i haven't tested the indirect call... hmm, should i deduplicate that code?
1 parent 982925e commit ff0c467

File tree

1 file changed

+92
-0
lines changed

1 file changed

+92
-0
lines changed

examples/host_coro.rs

Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,92 @@
1+
use eyre::{self, bail};
2+
use tinywasm::{
3+
types::{FuncType, ValType, WasmValue},
4+
CoroState, CoroStateResumeResult, Extern, FuncContext, HostCoroState, Imports, Module, PotentialCoroCallResult,
5+
Store, SuspendReason,
6+
};
7+
use wat;
8+
9+
const WASM: &str = r#"(module
10+
(import "host" "hello" (func $host_hello (param i32)))
11+
(import "host" "wait" (func $host_suspend (param i32)(result i32)))
12+
13+
(func (export "call_hello")
14+
(call $host_hello (i32.const -3))
15+
(call $host_suspend (i32.const 10))
16+
(call $host_hello)
17+
)
18+
)
19+
"#;
20+
21+
#[derive(Debug)]
22+
struct MyUserData {
23+
magic: u16,
24+
}
25+
26+
#[derive(Debug)]
27+
struct MySuspendedState {
28+
base: i32,
29+
}
30+
impl<'a> CoroState<Vec<WasmValue>, FuncContext<'a>> for MySuspendedState {
31+
fn resume(
32+
&mut self,
33+
_: FuncContext<'a>,
34+
arg: tinywasm::types::ResumeArgument,
35+
) -> tinywasm::Result<tinywasm::CoroStateResumeResult<Vec<WasmValue>>> {
36+
let val = arg.expect("you din't send").downcast::<i32>().expect("you sent wrong");
37+
return Ok(CoroStateResumeResult::Return(vec![WasmValue::I32(*val + self.base)]));
38+
}
39+
}
40+
41+
fn main() -> eyre::Result<()> {
42+
let wasm = wat::parse_str(WASM).expect("failed to parse wat");
43+
let module = Module::parse_bytes(&wasm)?;
44+
let mut store = Store::default();
45+
46+
let mut imports = Imports::new();
47+
imports.define(
48+
"host",
49+
"hello",
50+
Extern::typed_func(|_: FuncContext<'_>, x: i32| {
51+
println!("{x}");
52+
Ok(())
53+
}),
54+
)?;
55+
let my_coro_starter = |_ctx: FuncContext<'_>,
56+
vals: &[WasmValue]|
57+
-> tinywasm::Result<PotentialCoroCallResult<Vec<WasmValue>, Box<dyn HostCoroState>>> {
58+
let base = if let WasmValue::I32(v) = vals.first().expect("wrong args") { v } else { panic!("wrong arg") };
59+
let val_to_yield = Box::new(MyUserData { magic: 42 });
60+
let coro = Box::new(MySuspendedState { base: *base });
61+
return Ok(PotentialCoroCallResult::Suspended(SuspendReason::Yield(Some(val_to_yield)), coro));
62+
};
63+
imports.define(
64+
"host",
65+
"wait",
66+
Extern::func_coro(
67+
&FuncType { params: Box::new([ValType::I32]), results: Box::new([ValType::I32]) },
68+
my_coro_starter,
69+
),
70+
)?;
71+
72+
let instance = module.instantiate(&mut store, Some(imports))?;
73+
74+
let greeter = instance.exported_func_untyped(&store, "call_hello")?;
75+
let call_res = greeter.call_coro(&mut store, &[])?;
76+
let mut resumable = match call_res {
77+
tinywasm::PotentialCoroCallResult::Return(..) => bail!("it was supposed to return"),
78+
tinywasm::PotentialCoroCallResult::Suspended(SuspendReason::Yield(Some(val)), resumable) => {
79+
match val.downcast::<MyUserData>() {
80+
Ok(val) => assert_eq!( val.magic, 42 ),
81+
Err(_) => bail!("invalid yielded val"),
82+
}
83+
resumable
84+
}
85+
tinywasm::PotentialCoroCallResult::Suspended(..) => bail!("wrong suspend"),
86+
};
87+
88+
let final_res = resumable.resume(&mut store, Some(Box::<i32>::new(7)))?;
89+
assert!(final_res.finished());
90+
91+
Ok(())
92+
}

0 commit comments

Comments
 (0)