An example of running wasmtime as a host, with callbacks.
This commit is contained in:
commit
d0489776ee
|
@ -0,0 +1,2 @@
|
||||||
|
/target
|
||||||
|
**/target
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,12 @@
|
||||||
|
[package]
|
||||||
|
name = "rust-wasi-markdown"
|
||||||
|
version = "0.1.0"
|
||||||
|
edition = "2021"
|
||||||
|
|
||||||
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
anyhow = "1.0.70"
|
||||||
|
pulldown-cmark = "0.9.2"
|
||||||
|
structopt = "0.3.26"
|
||||||
|
wasmtime = "7.0.0"
|
|
@ -0,0 +1,11 @@
|
||||||
|
# Hello, World!
|
||||||
|
|
||||||
|
This is my first WASI program. Kinda sucks, huh?
|
||||||
|
|
||||||
|
> Don't say that!
|
||||||
|
|
||||||
|
But why not?
|
||||||
|
|
||||||
|
> Because this is cool.
|
||||||
|
|
||||||
|
Who says?
|
|
@ -0,0 +1,5 @@
|
||||||
|
(module
|
||||||
|
(func $hello (import "" "hello"))
|
||||||
|
(func (export "run") (call $hello)))
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,95 @@
|
||||||
|
use anyhow::Result;
|
||||||
|
use wasmtime::*;
|
||||||
|
|
||||||
|
struct MyState {
|
||||||
|
name: String,
|
||||||
|
count: usize,
|
||||||
|
}
|
||||||
|
|
||||||
|
const HELLO: &[u8; 78] =
|
||||||
|
b"(module (func $hello (import \"\" \"hello\")) (func (export \"run\") (call $hello)))";
|
||||||
|
|
||||||
|
fn main() -> Result<()> {
|
||||||
|
println!("Compiling module...");
|
||||||
|
|
||||||
|
// The Engine is the thing that manages and runs WASM instances.
|
||||||
|
let engine = Engine::default();
|
||||||
|
|
||||||
|
// The Module loads, compiles, and creates a new WASM module, ready to be
|
||||||
|
// run.
|
||||||
|
let module = Module::new(&engine, HELLO)?;
|
||||||
|
|
||||||
|
println!("Initializing...");
|
||||||
|
// The Store is where a WASM instance runs and includes its memory pages. It
|
||||||
|
// is the mechanism through which the host and guest programs interact.
|
||||||
|
let mut store = Store::new(
|
||||||
|
&engine,
|
||||||
|
MyState {
|
||||||
|
name: "hello world".to_string(),
|
||||||
|
count: 0,
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
println!("Creating callback...");
|
||||||
|
// A Func is a function defined by the host program and that can be called
|
||||||
|
// from a WASM module. Here, we're creating a host function that accesses
|
||||||
|
// data inside the store, and increments a mutable value within that data.
|
||||||
|
// Due to the nature of the store, all such functions end up as Fn: Send +
|
||||||
|
// Sync + 'static, with no 'FnMut' or 'FnOnce' defined, but the `Caller`
|
||||||
|
// type there still grants access to the inner workings. See the
|
||||||
|
// documentation for more.
|
||||||
|
let hello_func = Func::wrap(&mut store, |mut caller: Caller<'_, MyState>| {
|
||||||
|
println!("Calling back...");
|
||||||
|
println!("> {}, {}", caller.data().name, caller.data().count);
|
||||||
|
caller.data_mut().count += 1;
|
||||||
|
});
|
||||||
|
|
||||||
|
// An Instance is a running instance of the WASM module. By "running" I mean
|
||||||
|
// that it is now somewhere in memory and its functions can be called by the
|
||||||
|
// host. Note that the imports put *into* the instance are in order, not
|
||||||
|
// named, and must be extracted by a similarly ordered collection of imports
|
||||||
|
// on the other end.
|
||||||
|
println!("Instantiating module...");
|
||||||
|
let imports = [hello_func.into()];
|
||||||
|
let instance = Instance::new(&mut store, &module, &imports)?;
|
||||||
|
|
||||||
|
// Inside the module, we have a named export, "run". Here, we access it.
|
||||||
|
println!("Extracting import...");
|
||||||
|
let run = instance.get_typed_func::<(), ()>(&mut store, "run")?;
|
||||||
|
|
||||||
|
// And now we run it a couple of times. `run` calls `hello_func` defined
|
||||||
|
// above, and with each run the data persistent in the `store` object gets
|
||||||
|
// updated, so we can see the count rising:
|
||||||
|
println!("Running export...");
|
||||||
|
run.call(&mut store, ())?;
|
||||||
|
run.call(&mut store, ())?;
|
||||||
|
run.call(&mut store, ())?;
|
||||||
|
run.call(&mut store, ())?;
|
||||||
|
run.call(&mut store, ())?;
|
||||||
|
|
||||||
|
println!("Done!");
|
||||||
|
|
||||||
|
/*
|
||||||
|
The output should look like this:
|
||||||
|
|
||||||
|
Compiling module...
|
||||||
|
Initializing...
|
||||||
|
Creating callback...
|
||||||
|
Instantiating module...
|
||||||
|
Extracting import...
|
||||||
|
Running export...
|
||||||
|
Calling back...
|
||||||
|
> hello world, 0
|
||||||
|
Calling back...
|
||||||
|
> hello world, 1
|
||||||
|
Calling back...
|
||||||
|
> hello world, 2
|
||||||
|
Calling back...
|
||||||
|
> hello world, 3
|
||||||
|
Calling back...
|
||||||
|
> hello world, 4
|
||||||
|
Done!
|
||||||
|
*/
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
Loading…
Reference in New Issue