study-rust-wasm/rust-wasi-markdown/src/main.rs

96 lines
3.1 KiB
Rust

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(())
}