WasmEdge Rust SDK 釋出新版本

語言: CN / TW / HK

伴隨著 WasmEdge 0.10.1 釋出,WasmEdge Rust bindings 的全新版本也閃亮登場:wasmedge-sdk v0.2.0wasmedge-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 函式,我們需要一個 ImportObjectwasmedge-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-sdkModule 中定義了兩個方法:

  • 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)?;

在上面的程式碼中我們使用 ExecutorStore 來註冊 import 模組和已編譯模組。wasmedge-sdk 也提供其它 APIs 來做同樣的工作: Vm::register_import_moduleVm::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 還在開發中,期待社群的反饋。 下面是需要社群小夥伴幫助的類目。此外,針對每一次反饋,我們會寄出禮物作為感謝。在這裡檢視規則

  • 試試 wasmedge-sdk,讓我們知道如何改進。 此外,如果有任何問題,請提 issue
  • Bug 報告。 不可避免地,有一些我們沒有涵蓋的邊緣測試用例。 如果發現新的 bug,請隨時提出 issue 並告訴我們。
  • 檢視文件。 文件對於開源軟體來說是必不可少的。 如果發現文件有問題,請不要猶豫提 issue 或建立 PR 來修正。
  • 提出功能需求。 wasmedge-sdk 目前的特性來自我們使用者的真實需求。 如果你有想到好的主意,請通過 issue 告訴我們。