伴随着 WasmEdge 0.10.1 发布,WasmEdge Rust bindings 的全新版本也闪亮登场:wasmedge-sdk v0.2.0
和wasmedge-sys v0.8.0
。 你可以在 这里 找到相关 API 文档和源代码。
下图显示了 WasmEdge Rust bindings 的架构。 wasmedge-sys
crate 定义了一组低级 Rust API,它们简单地包了 WasmEdge C-API 并提供相应的安全版本,而 wasmedge-sdk
定义了一组围绕应用程序的高级 Rust API。
我们建议大多数应用程序开发者使用 wasmedge-sdk
crate。 因此,本文将重点介绍 wasmedge-sdk
。 如果对 WasmEdge 低级 Rust API 的内部情况感兴趣,请可以查看wasmedge-sys
源代码。
WasmEdge Rust bindings SDK 使 Rust 应用程序能够嵌入 WebAssembly 函数或模块。 这对于基于 Rust 的云原生或区块链基础设施软件特别有用,因为它们需要以安全有效的方式支持不受信任的用户函数。
wasmedge-sdk
crate 的主要设计目标是使开发者能够使用 WasmEdge 轻松安全地将第三方代码合并到他们的 rust 应用程序中。 wasmedge-sdk
crate 旨在为 Rust 开发者提供顺滑的体验。
下面让我们来看一个简单的例子吧!
从 wasmedge-sdk
开始
这个例子展示了如何从 Rust 程序运行 WasmEdge host 函数。 该函数也是用 Rust 编写的。 你也可以使用 C、TinyGo 或 JavaScript 等编程语言编写 WasmEdge 函数。
这里我们使用一个简单的 hello world
程序来解释 wasmedge-sdk
是如何工作的。 此示例演示了如何完成以下工作。
1.通过ImportObjectBuilder
加载第三方 native 函数 2.加载 native 函数生成的 Wasm 模块
有关
wasmedge-sdk
的更多示例,请查看此处。
首先,确保已经在本地系统上安装了 Rust 和 WasmEdge。 如果想使用 WasmEdge 的 WasmEdgeProcess
插件,请注意 Linux
是唯一支持的操作系统。
接下来,从 WasmEdge repo 中获取 wasmedge-sdk
示例。
$ git clone https://github.com/WasmEdge/WasmEdge.git
$ cd /bindings/rust/
然后,使用下面的命令行从 wasmedge-sdk 文件运行 hello world 示例。
cargo run -p wamedge-sdk --example hello_world -- --nocapture
如果命令行成功运行,会看到 Hello, world!
在终端中打印出来,如下图所示。
现在让我们深入研究代码。 上述 Hello World
示例的源代码可以在这里找到。
让我们立即获取所有 imports 并开始:
// 如果使用 < 1.63 版本的 rust,请添加此特性
// #![feature(explicit_generic_args_with_impl_trait)]
use wasmedge_sdk::{params, Executor, ImportObjectBuilder, Module, Store};
use wasmedge_sys::WasmValue;
use wasmedge_types::wat2wasm;
定义一个 native 函数并创建一个 ImportObject
首先,让我们定义一个名为 say_hello_world
的 native 函数,它会打印出 Hello, World!
。
fn say_hello_world(_inputs: Vec<WasmValue>) -> Result<Vec<WasmValue>, u8> {
println!("Hello, world!");
Ok(vec![])
}
要在 WasmEdge
runtime 中使用 native 函数作为 import 函数,我们需要一个 ImportObject
。 wasmedge-sdk
定义了一个 ImportObjectBuilder,它提供了一组用于创建 ImportObject
的 chaining 方法。我们看看具体方法:
// 创建一个 import 模块
let import = ImportObjectBuilder::new()
.with_func::<(), ()>("say_hello", say_hello_world)?
.build("env")?;
现在,我们有一个名为 env
的 import 模块,它包含一个 host 函数 say_hello
。 也许你注意到,我们用于 import 模块和 host 函数的名称与 Wasm 模块中出现的名称完全相同。 可以在下一节中找到 Wasm 模块。
加载一个 wasm 模块
现在我们加载一个 Wasm 模块。 wasmedge-sdk
在 Module
中定义了两个方法:
-
from_file 从文件加载一个 Wasm 模块,并且同时验证已经加载的模块。
-
from_bytes 从内存字节数组中加载一个 Wasm 模块,同时验证加载的 Wasm 模块。
这里我们选择使用 Module::from_bytes
方法从内存字节数组中加载我们的 Wasm 模块。
let wasm_bytes = wat2wasm(
br#"
(module
;; First we define a type with no parameters and no results.
(type $no_args_no_rets_t (func (param) (result)))
;; Then we declare that we want to import a function named "env" "say_hello" with
;; that type signature.
(import "env" "say_hello" (func $say_hello (type $no_args_no_rets_t)))
;; Finally we create an entrypoint that calls our imported function.
(func $run (type $no_args_no_rets_t)
(call $say_hello))
;; And mark it as an exported function named "run".
(export "run" (func $run)))
"#,
)?;
// 从给定的内存字节加载一个 Wasm 模块并返回一个编译的模块
let module = Module::from_bytes(None, &wasm_bytes)?;
注册 import 模块和编译模块
要注册一个已编译的模块,我们需要检查它是否依赖于某些 import 模块。 在 Wasm 模块中,这条语句 (import "env" "say_hello" (func $say_hello (type $no_args_no_rets_t)))
告诉我们,它依赖于一个名为 env
的 import 模块。 因此,在注册编译好的 wasm 模块之前,我们需要先注册 import 模块。
// 创建一个 executor
let mut executor = Executor::new(None, None)?;
// 创一个 store
let mut store = Store::new()?;
// 将 import 模块注册到 store 中
store.register_import_module(&mut executor, &import)?;
// 将编译好的模块注册到 store 中,并得到一个模块实例
let extern_instance = store.register_named_module(&mut executor, "extern", &module)?;
在上面的代码中我们使用 Executor 和 Store 来注册 import 模块和已编译模块。wasmedge-sdk
也提供其它 APIs 来做同样的工作: Vm::register_import_module 和 Vm::register_module_from_bytes。
运行导出的函数
现在可以运行导出的函数。
// 获取导出的函数 "run"
let run = extern_instance
.func("run")
.ok_or_else(|| anyhow::Error::msg("Not found exported function named 'run'."))?;
// 运行 host 函数
run.call(&mut executor, params!())?;
展望未来
很快,wasmedge-sdk
将添加对嵌入式 Wasm 和异步 host 函数的异步调用的支持。 另一个重要特性是支持 wasmedge-sdk
中的复杂接口类型,允许开发者将复杂的数据结构(如字符串和用户定义的复杂类型)传递给 Wasm VM。
为 wasmedge-sdk 的开发做贡献
wasmedge-sdk 还在开发中,期待社区的反馈。 下面是需要社区小伙伴帮助的类目。此外,针对每一次反馈,我们会寄出礼物作为感谢。在这里查看规则。