wasm-bindgen 溝通型別

在 Rust/JS 型別之間轉換時,最後要討論的一個方面是如何實際傳達此資訊。 #[wasm_bindgen] 巨集在 Rust 程式碼的語法(未解析)結構上執行,然後負責產生 wasm-bindgen CLI 工具稍後讀取的資訊。

為了實現這一點,採取了一種稍微非常規的方法。關於 Rust 程式碼結構的靜態資訊透過 JSON(目前)序列化到 Wasm 可執行檔的自訂區段。其他資訊,例如型別實際上是什麼,不幸的是在編譯器的後期才會知道,因為有相關型別投影和 typedef 等因素。事實證明,我們還想將 `FnMut(String, Foo, &JsValue)` 之類的「豐富」型別傳達給 `wasm-bindgen` CLI,處理所有這些非常棘手!

為了解決這個問題,#[wasm_bindgen] 巨集產生「描述導入或匯出型別簽章」的**可執行函式**。這些可執行函式就是 `WasmDescribe` 特性的全部內容

#![allow(unused)]
fn main() {
pub trait WasmDescribe {
    fn describe();
}
}

儘管表面上很簡單,但此特性實際上非常重要。當您編寫像這樣的匯出時

#![allow(unused)]
fn main() {
#[wasm_bindgen]
fn greet(a: &str) {
    // ...
}
}

除了我們上面討論的 JS 產生 的 shim 之外,該巨集 *還* 會產生類似以下的內容

#[no_mangle]
pub extern "C" fn __wbindgen_describe_greet() {
    <dyn Fn(&str)>::describe();
}

換句話說,它產生對 `describe` 函式的調用。這樣做時,`__wbindgen_describe_greet` shim 是對導入/匯出型別佈局的程式化描述。這些會在 `wasm-bindgen` 執行時執行!這些執行依賴於一個名為 `__wbindgen_describe` 的導入,該導入將一個 `u32` 傳遞給主機,並且在多次調用時,會有效地給出一個 `Vec<u32>`。然後,可以將此 `Vec<u32>` 重新解析為完全描述型別的 `enum Descriptor`。

總之,這有點迂迴,但不應該對產生的程式碼或運行時有任何影響。所有這些描述符函式都會從發出的 Wasm 檔案中刪除。