The below WAT, adapted from a couple of Wasmtime examples, runs absolutely fine embedded in my application but what I thought was the equivalent Rust code fails with:
Running `target\debug\hello_world.exe`
Error: expected 5 imports, found 1
error: process didn't exit successfully: `target\debug\hello_world.exe` (exit code: 1)
Here's the working WAT:
(module
(import "host" "greet" (func $greet (param i32 i32)))
(func (export "run")
i32.const 4 ;; ptr
i32.const 22 ;; len
call $greet)
(memory (export "memory") 1)
(data (i32.const 4) "Calling back from WAT!")
)
And the failing Rust:
use std::ffi::CString;
#[link(wasm_import_module = "host")]
extern "C" {
fn greet(ptr: i32, len: i32);
}
static GREETING: &str = "Calling back from Rust!";
#[no_mangle]
pub extern "C" fn run() {
let greeting = CString::new(GREETING).expect("contains null byte");
let ptr = greeting.as_ptr();
std::mem::forget(ptr);
unsafe {
greet(ptr as i32, GREETING.len() as i32);
}
}
My minimal example app that embeds the WASM modules:
use std::str;
use anyhow::Result;
use wasmtime::{Caller, Engine, Extern, Func, Instance, Module, Store};
struct MyState {
name: String,
count: usize,
}
fn main() -> Result<()> {
let engine = Engine::default();
let code = include_bytes!("../hello.wat");
let module = Module::new(&engine, code)?;
let mut store = Store::new(
&engine,
MyState {
name: "Hello, junglie85!".to_string(),
count: 0,
},
);
let greet_func = Func::wrap(
&mut store,
|mut caller: Caller<'_, MyState>, ptr: i32, len: i32| {
let mem = match caller.get_export("memory") {
Some(Extern::Memory(mem)) => mem,
_ => anyhow::bail!("failed to find host memory"),
};
let data = mem
.data(&caller)
.get(ptr as u32 as usize..)
.and_then(|arr| arr.get(..len as u32 as usize));
let string = match data {
Some(data) => match str::from_utf8(data) {
Ok(s) => s,
Err(_) => anyhow::bail!("invalid utf-8"),
},
None => anyhow::bail!("pointer/length out of bounds"),
};
println!("> {} {}", caller.data().name, string);
caller.data_mut().count += 1;
Ok(())
},
);
let imports = [greet_func.into()];
let instance = Instance::new(&mut store, &module, &imports)?;
let run = instance.get_typed_func::<(), ()>(&mut store, "run")?;
println!("# Global count = {}", store.data().count);
run.call(&mut store, ())?;
println!("# Global count = {}", store.data().count);
Ok(())
}
What is the Rust equivalent of the WAT example?