At a high level I am trying to create a Rust host program that loads a WASM module at runtime using Wasmtime and calls a WASM function that returns a string. I can get this working with numeric types such as usize
, but can't work out how to handle strings (or other complex types).
In my plugin crate I have a lib.rs
that I compile with cargo build --target=wasm32-unknown-unknown --release
:
use std::ffi::CString;
use std::os::raw::c_char;
static PLUGIN_NAME: &'static str = "Test Plugin";
#[no_mangle]
pub extern "C" fn plugin_name() -> *mut c_char {
let s = CString::new(PLUGIN_NAME).unwrap();
s.into_raw()
}
#[no_mangle]
pub fn plugin_name_len() -> usize {
PLUGIN_NAME.len()
}
This is based on code in one of the answers to this question which is close to what I'm looking for, but uses JavaScript on the host side.
In my host crate I have a main.rs
:
use wasmtime::{Engine, Linker, Module, Store};
use wasmtime_wasi::WasiCtxBuilder;
fn main() -> anyhow::Result<()> {
let engine = Engine::default();
let Some(file) = std::env::args().nth(1) else {
anyhow::bail!("USAGE: host <WASM FILE>");
};
let module = Module::from_file(&engine, file)?;
let linker = Linker::new(&engine);
let wasi = WasiCtxBuilder::new()
.inherit_stdio()
.inherit_args()
.expect("should always be able to inherit args")
.build();
let mut store = Store::new(&engine, wasi);
let instance = linker.instantiate(&mut store, &module)?;
let Ok(plugin_name_len) = instance.get_typed_func::<(), u32>(&mut store, "plugin_name_len") else {
anyhow::bail!("Failed to get plugin_name_len");
};
let len = plugin_name_len.call(&mut store, ())?;
println!("Length: {}", len);
let Ok(plugin_name) = instance.get_typed_func::<(), &str>(&mut store, "plugin_name") else {
anyhow::bail!("Failed to get plugin_name");
};
Ok(())
}
But that doesn't compile as you can't use &str
in a call to instance.get_typed_func()
Could someone share an example (and an explanation) of how to call a WASM function that returns a string from a Rust Wasmtime host program?