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