将类型传递给 wasm-bindgen

当在 Rust/JS 类型之间相互转换时,最后要讨论的方面是如何实际传递这些信息。 #[wasm_bindgen] 宏运行在 Rust 代码的语法结构(未解析的)之上,然后负责生成 wasm-bindgen CLI 工具稍后读取的信息。

为了实现这一点,采用了一种稍微非常规的方法。关于 Rust 代码结构的静态信息通过 JSON(当前)序列化到 Wasm 可执行文件的自定义部分。其他信息,例如类型实际是什么,不幸的是在编译器后期才知道,因为诸如关联类型投影和类型定义之类的事情。事实证明,我们还想向 wasm-bindgen CLI 传递诸如 FnMut(String, Foo, &JsValue) 之类的“丰富”类型,而处理所有这些都非常棘手!

为了解决这个问题,#[wasm_bindgen] 宏生成了可执行函数,这些函数“描述导入或导出的类型签名”。这些可执行函数就是 WasmDescribe trait 的全部意义


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

虽然看起来很简单,但此 trait 实际上非常重要。当您编写如下导出时


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

除了我们上面谈到的 JS 生成的垫片之外,宏生成类似的内容

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

或者换句话说,它生成了 describe 函数的调用。通过这样做,__wbindgen_describe_greet 垫片是对导入/导出的类型布局的程序化描述。然后在 wasm-bindgen 运行时执行这些描述!这些执行依赖于一个名为 __wbindgen_describe 的导入,该导入将一个 u32 传递给主机,并且在多次调用时有效地给出一个 Vec<u32>。然后,可以将此 Vec<u32> 重新解析为完全描述类型的 enum Descriptor

总而言之,这有点绕弯子,但根本不应该对生成的代码或运行时产生任何影响。所有这些描述符函数都从发出的 Wasm 文件中删除。