|
| 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