在 Rust 程序和嵌入式 WebAssembly 运行时之间进行通信的最佳实践是啥?

Posted

技术标签:

【中文标题】在 Rust 程序和嵌入式 WebAssembly 运行时之间进行通信的最佳实践是啥?【英文标题】:What is the best practice to communicate between a Rust program and an embedded WebAssembly runtime?在 Rust 程序和嵌入式 WebAssembly 运行时之间进行通信的最佳实践是什么? 【发布时间】:2020-08-15 03:49:13 【问题描述】:

我正在开发一个 Rust 程序,我想在运行时使用 WebAssembly 作为脚本语言来驱动其行为。我们假设脚本也是用 Rust 编写的。我已经阅读了 Wasmer、Wasmtime 和 Lucet 的教程,虽然导出/导入的函数可以作为参数并返回 WASM 原始类型,但似乎没有简单/无痛的解决方案可以在 Rust 二进制文件和 WASM 脚本之间传递任意数据在其中运行。特别是字符串,必须由manually passing a primitive as a sort of pointer 处理到运行时的线性内存和长度。

wasm-bindgen 似乎可以解决我的问题,但它只针对浏览器中的 WASM-JS 通信。 Wasmer 和 Wasmtime 有 *-interface-types crates,但它们没有教程,并且是实验性的,可能会发生变化。我不需要通过structs,但我想实现这样的目标:

// in the host program
let argument: &[u8] = &[0, 1... n]; // dumb byte slice
let guest_result: Vec<u8> = wasm_runtime.call("guest_function", &[argument]);
// in the guest WASM library/script
let data_from_host: Vec<u8> = imported_function(some_other_bytes);

只需通过和返回Vec&lt;u8&gt;s 或&amp;[u8]s 两种方式就足够了,我可以使用bincode 或其他方式反序列化它们。有没有人做到这一点?我可以像使用字符串一样共享线性内存,但这似乎不安全,尤其是在多个线程上使用多个脚本时。

tl;dr 我想使用 WASM 作为脚本语言并与 &amp;[u8]Vec&lt;u8&gt; 对话,但没有找到任何简单的方法。

【问题讨论】:

【参考方案1】:

这个可用性问题是已知的,似乎正在积极处理中:https://hacks.mozilla.org/2019/08/webassembly-interface-types/

以下是该帖子中一些结束语的后续内容:https://github.com/bytecodealliance/wasmtime/issues/677

我几乎没有编写 C 或处理系统调用接口的经验,因此传递值对我来说也很麻烦。在大多数情况下,我只是花时间构建更高级别的抽象(就像 wasm-bindgen 所做的那样),以便我可以更轻松地传递数据。

例如,wasi 提供了一个您可以实现的接口,并且它们抽象出所有繁琐的部分:https://docs.rs/crate/wasi/0.9.0+wasi-snapshot-preview1/source/src/lib_generated.rs 您可以在此处看到 lucet 实现它:https://github.com/bytecodealliance/lucet/blob/master/lucet-wasi/src/runtime.rs

除非您尝试实现 wasi,否则我认为这不会对您有太大帮助,但它是实现您想要的那种抽象的一个很好的例子。

【讨论】:

以上是关于在 Rust 程序和嵌入式 WebAssembly 运行时之间进行通信的最佳实践是啥?的主要内容,如果未能解决你的问题,请参考以下文章

Rust & WebAssembly 翻译系列 为什么选择Rust和WebAssembly?

使用 Docker 管理用 Rust 编写的 WebAssembly 程序

Lightly:新一代的 Rust IDE

Rust + Go 双剑合璧:WebAssembly 领域应用

入门 Rust 开发 WebAssembly

Rust开发WebAssembly在Html和Vue中的应用后篇