將類型傳達給 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_variables)] #fn main() { pub trait WasmDescribe { fn describe(); } #}
雖然看似簡單,但此特性實際上非常重要。當您編寫如下的導出時
# #![allow(unused_variables)] #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 檔案中刪除。