與 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 檔案中刪除。