在高层次上,我试图创建一个Rust主机程序,该程序在运行时使用Wasmtime加载WASM模块,并调用返回字符串的WASM函数。我可以让这个工作与数字类型,如usize
,但不能解决如何处理字符串(或其他复杂类型)。
在我的插件箱中,我有一个lib.rs
,我用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 question的一个答案中的代码,它接近我正在寻找的,但在主机端使用JavaScript。
在我的主机箱中,我有一个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(())
}
型
但是这不会编译,因为您不能在对instance.get_typed_func()
的调用中使用&str
有人能分享一个例子(和解释)如何调用WASM函数,从Rust Wasmtime主机程序返回字符串吗?
1条答案
按热度按时间dxxyhpgq1#
我已经搞定了。
TL;DR是插件WASM函数
plugin_name()
返回一个32位整数,它实际上是指向WASM内存的指针。要访问WASM内存,您需要通过从Instance
访问"memory"
导出来获取WasmtimeMemory
结构体。然后,您可以使用从调用plugin_name()
获得的32位整数作为字符串第一个字符的偏移量,并将此偏移量+字符串的长度作为最后一个字符。将这片u8
s转换为Vec,并将其输入String::from_utf8()
,您就得到了String
!已更新,正在运行,
main.rs
:字符串
注意-我正在将
len
和ptr
从u32
转换为usize
,以便我可以使用它们从Rust索引到WASM内存。