Last active
August 13, 2020 07:24
-
-
Save peterhuene/9eb00781112fea84bad5f8c4f9b70cef to your computer and use it in GitHub Desktop.
async host function
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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(()) | |
} |
Author
peterhuene
commented
Aug 13, 2020
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment