Kei*_*arp 3 rust webassembly wasmtime rust-wasm
在较高级别上,我尝试创建一个 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()
}
Run Code Online (Sandbox Code Playgroud)
这是基于这个问题的答案之一中的代码,该代码与我正在寻找的内容很接近,但在主机端使用 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(())
}
Run Code Online (Sandbox Code Playgroud)
但这不会编译,因为你不能&str在调用中使用instance.get_typed_func()
有人可以分享一个如何调用从 Rust Wasmtime 主机程序返回字符串的 WASM 函数的示例(和解释)吗?
我已经完成了这个工作。
TL;DR 插件 WASM 函数plugin_name()返回一个 32 位整数,它实际上是指向 WASM 内存的指针。要访问 WASM 内存,您需要Memory通过"memory"访问Instance. 然后,您可以使用从调用中获得的 32 位整数plugin_name()作为字符串第一个字符的偏移量,并将该偏移量 + 字符串的长度作为最后一个字符。将这片u8s 转换为 Vec 并将其输入String::from_utf8(),你就得到了一个String!
已更新,正在运行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, ())? as usize;
let Ok(plugin_name) = instance.get_typed_func::<(), u32>(&mut store, "plugin_name") else {
anyhow::bail!("Failed to get plugin_name");
};
let ptr = plugin_name.call(&mut store, ())? as usize;
let Some(memory) = instance.get_memory(&mut store, "memory") else {
anyhow::bail!("Failed to get WASM memory");
};
let data = memory.data(&store)[ptr..(ptr + len)].to_vec();
let name = String::from_utf8(data)?;
println!("Plugin name: {}", name);
Ok(())
}
Run Code Online (Sandbox Code Playgroud)
注意 - 我正在将len和ptr从转换u32为usize,以便我可以使用它们从 Rust 索引到 WASM 内存。
| 归档时间: |
|
| 查看次数: |
1081 次 |
| 最近记录: |