将类型传达给 `wasm-bindgen`

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

为了实现这一点,采用了稍微不寻常的方法。关于 Rust 代码结构的静态信息通过 JSON(目前)序列化到 wasm 可执行文件的自定义部分。其他信息,比如类型实际上是什么,不幸的是直到编译器后面的阶段才知道,因为存在关联类型投影和类型定义之类的东西。事实证明,我们还想将“丰富”类型(如 `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 生成的垫片之外,宏还生成类似于

#[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 文件中修剪掉。