Skip to content

Instantly share code, notes, and snippets.

@peterhuene
Last active August 13, 2020 07:24
Show Gist options
  • Save peterhuene/9eb00781112fea84bad5f8c4f9b70cef to your computer and use it in GitHub Desktop.
Save peterhuene/9eb00781112fea84bad5f8c4f9b70cef to your computer and use it in GitHub Desktop.
async host function
use anyhow::Result;
use async_std::task;
use futures::FutureExt;
use generator::{done, Gn};
use std::boxed::Box;
use std::cell::RefCell;
use std::future::Future;
use std::pin::Pin;
use std::time::Duration;
use wasmtime::{Config, Engine, Func, Instance, Module, Store};
type Scope<'a> = generator::Scope<'a, i32, Pin<Box<dyn Future<Output = i32> + Send>>>;
async fn foo() -> i32 {
println!("async host function `foo` was called.");
task::spawn_local(async {
loop {
println!("working in another task...");
task::sleep(Duration::from_secs(1)).await;
}
});
println!("sleeping host function for 5 seconds...");
// Switch the following lines to see the non-blocking vs. blocking behavior
task::sleep(Duration::from_secs(5)).await;
//std::thread::sleep(Duration::from_secs(5));
println!("sleep completed.");
12345
}
#[async_std::main]
async fn main() -> Result<()> {
const STACK_SIZE: usize = 0x1000;
let engine = Engine::new(&Config::new().max_wasm_stack(STACK_SIZE));
let wat = r#"
(module
(import "" "foo" (func $foo (result i32)))
(func (export "run") (result i32)
call $foo
)
)
"#;
let module = Module::new(&engine, wat)?;
let mut g = Gn::new_scoped_opt(STACK_SIZE, move |scope: Scope<'_>| {
// This code is running on a different stack
let store = Store::new(module.engine());
// UNSAFE HACK: this is "safe" so long as the instance doesn't outlive the scope
let scope: RefCell<Scope<'static>> = unsafe { RefCell::new(std::mem::transmute(scope)) };
let f = Func::wrap(&store, move || {
// Yield a future to the main loop (this will switch stacks)
scope.borrow_mut().yield_(foo().boxed()).unwrap()
});
// NOTE: the instance must not outlive the passed scope
let instance = Instance::new(&store, &module, &[f.into()]).unwrap();
let run = instance.get_func("run").unwrap().get0::<i32>().unwrap();
println!("wasm function `run` returned: {}.", run().unwrap());
done!()
});
// Resuming the generator switches to the generator's stack
while let Some(f) = {
println!("resuming generator.");
g.resume()
} {
// Send the result of the future back to the generator
g.set_para(f.await);
}
Ok(())
}
@peterhuene
Copy link
Author

resuming generator.
async host function `foo` was called.
sleeping host function for 5 seconds...
working in another task...
working in another task...
working in another task...
working in another task...
working in another task...
sleep completed.
resuming generator.
wasm function `run` returned: 12345.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment