rust 调用从Wasmtime返回字符串的WASM函数

vlurs2pr  于 2023-08-05  发布在  其他
关注(0)|答案(1)|浏览(205)

在高层次上,我试图创建一个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主机程序返回字符串吗?

dxxyhpgq

dxxyhpgq1#

我已经搞定了。
TL;DR是插件WASM函数plugin_name()返回一个32位整数,它实际上是指向WASM内存的指针。要访问WASM内存,您需要通过从Instance访问"memory"导出来获取Wasmtime Memory结构体。然后,您可以使用从调用plugin_name()获得的32位整数作为字符串第一个字符的偏移量,并将此偏移量+字符串的长度作为最后一个字符。将这片u8 s转换为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(())
}

字符串
注意-我正在将lenptru32转换为usize,以便我可以使用它们从Rust索引到WASM内存。

相关问题