WebAssembly Interfaces (WAI)
The WebAssembly spec that was first released in 2017 was only a minimum viable product and deliberately left several features incomplete to be iterated on by the ecosystem.
Arguably the most important functionality gap is the fact that only WebAssembly primitives can be passed between the host and guest. That means imports and exports can only use the following data types,
i32
- signed 32-bit integersi64
- signed 64-bit integersf32
- a 32-bit floatf64
- a 64-bit float (often called adouble
)funcref
- a reference to a WebAssembly functionexternref
- a reference to some opaque object owned by the WebAssembly virtual machine
You'll notice this list doesn't even include strings or boolean values!
The WebAssembly Interfaces project (WAI for short) provides a polyfill for
passing around higher-level objects. It lets developers define their imports and
exports in a *.wai
file, then uses wai-bindgen
to generate glue which
automagically passes things around within the constraints of WebAssembly.
There are four main parts to WAI:
- The
*.wai
file - The WAI Bindgen code generator
- The guest
- The host
The Wasmer Pack project provides a convenient way to consume WebAssembly packages which implement a WAI interface.
Some useful links:
- The
wasmerio/wai
repository (opens in a new tab) - The
*.wai
format (opens in a new tab) - The
wai-bindgen
CLI on crates.io (opens in a new tab)
The *.wai
File
WAI uses a file (or files) with the *.wai
extension to define the host-guest
interface for an application that uses WebAssembly.
The items in a *.wai
file map closely to concepts shared by most programming
languages. It has types, interfaces
("Resources"), structs ("Records"),
functions, enums, and so on.
The precise syntax is defined in the WAI repository (opens in a new tab) and a parser,
wai-parser
(opens in a new tab), is available as a Rust crate.
The Guest
In an application using WebAssembly, the "guest" is the code that has been compiled to WebAssembly and is being loaded into a WebAssembly virtual machine.
The Host
In an application using WebAssembly, the "host" is the code that uses a
WebAssembly virtual machine (like wasmer
(opens in a new tab)) to load a guest and use
functionality it provides.
The WebAssembly spec refers to the host in some places as the embedder (opens in a new tab).
WAI Bindgen
The WAI Bindgen code generator consumes *.wai
files and generates glue code
that the host can use for using functionality from a WebAssembly
module or the guest can use for implementing that functionality.
There are two primary ways users will interact with WAI Bindgen, the
wai-bindgen
CLI, and the wai-bindgen-*
family of crates.
The wai-bindgen
CLI provides a command-line interface to the wai-bindgen-*
crates, and is often used for once-off investigation or integration with a
non-Rust build system.
On the other hand, the wai-bindgen-*
crates allow users to generate bindings
programmatically and give them much more control over the generation process.
Language | Direction | Code Generator | Procedural Macro |
---|---|---|---|
Rust | Guest | wai-bindgen-gen-rust-wasm (opens in a new tab) | wai-bindgen-rust (opens in a new tab) |
Rust | Host (Wasmer) | wai-bindgen-gen-wasmer (opens in a new tab) | wai-bindgen-wasmer (opens in a new tab) |
Rust | Host (Wasmtime) | wai-bindgen-gen-wasmtime (opens in a new tab) | wai-bindgen-wasmtime (opens in a new tab) |
C | Guest | wai-bindgen-gen-c (opens in a new tab) | |
JavaScript | Host | wai-bindgen-gen-js (opens in a new tab) | |
Python | Host (Wasmer) | wai-bindgen-gen-wasmer-py (opens in a new tab) | |
Python | Host (Wasmtime) | wai-bindgen-gen-wasmtime-py (opens in a new tab) |