blob: d8684b2f8bcbada057a50cc7972bdedb96ed54ab [file] [log] [blame] [view]
# Communicating types to `wasm-bindgen`
The last aspect to talk about when converting Rust/JS types amongst one another
is how this information is actually communicated. The `#[wasm_bindgen]` macro is
running over the syntactical (unresolved) structure of the Rust code and is then
responsible for generating information that `wasm-bindgen` the CLI tool later
reads.
To accomplish this a slightly unconventional approach is taken. Static
information about the structure of the Rust code is serialized via JSON
(currently) to a custom section of the wasm executable. Other information, like
what the types actually are, unfortunately isn't known until later in the
compiler due to things like associated type projections and typedefs. It also
turns out that we want to convey "rich" types like `FnMut(String, Foo,
&JsValue)` to the `wasm-bindgen` CLI, and handling all this is pretty tricky!
To solve this issue the `#[wasm_bindgen]` macro generates **executable
functions** which "describe the type signature of an import or export". These
executable functions are what the `WasmDescribe` trait is all about:
```rust
pub trait WasmDescribe {
fn describe();
}
```
While deceptively simple this trait is actually quite important. When you write,
an export like this:
```rust
#[wasm_bindgen]
fn greet(a: &str) {
// ...
}
```
In addition to the shims we talked about above which JS generates the macro
*also* generates something like:
```
#[no_mangle]
pub extern "C" fn __wbindgen_describe_greet() {
<dyn Fn(&str)>::describe();
}
```
Or in other words it generates invocations of `describe` functions. In doing so
the `__wbindgen_describe_greet` shim is a programmatic description of the type
layouts of an import/export. These are then executed when `wasm-bindgen` runs!
These executions rely on an import called `__wbindgen_describe` which passes one
`u32` to the host, and when called multiple times gives a `Vec<u32>`
effectively. This `Vec<u32>` can then be reparsed into an `enum Descriptor`
which fully describes a type.
All in all this is a bit roundabout but shouldn't have any impact on the
generated code or runtime at all. All these descriptor functions are pruned from
the emitted wasm file.