如何在 Rust 程序中運行 WASM

這篇文章將探索如何在 Rust 應用程序中嵌入 Web Assembly 代碼。我們依賴於 wasmtime,wasmtime 是 WebAssembly 的一個獨立運行時。

創建項目

讓我們從創建一個新的 Rust 項目開始:

$ cargo new rustwasm
$ cd rustwasm

接下來,讓我們安裝幾個 crate:

$ cargo add anyhow
$ cargo add wasmtime

我們在 main.rs 文件中寫入如下代碼:

use anyhow::Result;
use wasmtime::*;

fn main() -> Result<(){
    println!("Compiling module...");
    let engine = Engine::default();
    let module = Module::from_file(&engine, "hello.wat")?; //(1)

    println!("Initializing...");
    let mut store = Store::new(
        &engine,
        ()
    ); //(2)

    println!("Creating callback...");
    let hello_func = Func::wrap(&mut store, |_caller: Caller<'_, ()>| {
        println!("Calling back...");
    }); //(3)

    println!("Instantiating module...");
    let imports = [hello_func.into()];
    let instance = Instance::new(&mut store, &module, &imports)?;

    println!("Extracting export...");
    let run = instance.get_typed_func::<()()>(&mut store, "run")?; //(4)

    println!("Calling export...");
    run.call(&mut store, ())?; //(5)

    println!("Done.");
    Ok(())
}

第一步:

我們從磁盤加載一個模塊開始。我們正在裝載 hello.wat,默認情況下,將 Web Assembly 代碼發佈成二進制形式。然而,爲了我們的目的,我們依賴於文本表示 (wat)。

第二步:

當運行 wasm 代碼時我們還希望在 host 和 wasm 代碼之間共享一些狀態。通過 Store,我們可以共享這個上下文。在我們的例子中,我們現在不需要共享任何狀態。因此,我們指定一個 Unit 類型作爲 Store::new 的第二個參數。

第三步:

在本文中,我們想讓一個 Rust 函數在 wasm 代碼中可用,然後調用。我們用 Func::wrap 包裝一個 Rust 閉包。這個函數不接受任何參數,而且也不返回任何東西;它只是在調用時打印出 “Calling back”。

第四步:

Wasm 代碼默認情況下沒有主函數,我們把它當做 lib。在我們的例子中,我們期望出現一個 run 函數,我們將使用它作爲我們的入口點。

在調用函數之前,首先需要檢索它。我們還使用 get_typed_func 來指定它的類型簽名。如果我們在二進制文件中找到它,就可以調用它。

第五步:

現在我們找到了函數,讓我們調用它。

Web Assembly 代碼

Rust 程序就緒後,讓我們來看看我們想要加載的 wasm 代碼。在項目根目錄下新建一個 hello.wat 文件:

(module
  (func $hello (import "" "hello"))
  (func (export "run") (call $hello))
)

wasm 文本格式使用 lisp 語言的 s 表達式。s 表達式是一種非常古老且非常簡單的表示樹的文本格式,因此我們可以將模塊視爲描述模塊結構及其代碼的節點樹。

與編程語言的抽象語法樹不同,WebAssembly 的樹非常扁平,主要由指令列表組成。

這個小程序執行三個任務:

如前所述,.wat(與二進制表示相同) 不是我們通常手寫的東西,而是由工具生成的。

運行

所有組件就緒後,讓我們運行它:

Compiling module...
Initializing...
Creating callback...
Instantiating module...
Extracting export...
Calling export...
Calling back...
Done.
本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源https://mp.weixin.qq.com/s/qmmJi1Gwz7nZPE47tNnNaQ