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 integers
  • i64 - signed 64-bit integers
  • f32 - a 32-bit float
  • f64 - a 64-bit float (often called a double)
  • funcref - a reference to a WebAssembly function
  • externref - 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 *.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.

LanguageDirectionCode GeneratorProcedural Macro
RustGuestwai-bindgen-gen-rust-wasm (opens in a new tab)wai-bindgen-rust (opens in a new tab)
RustHost (Wasmer)wai-bindgen-gen-wasmer (opens in a new tab)wai-bindgen-wasmer (opens in a new tab)
RustHost (Wasmtime)wai-bindgen-gen-wasmtime (opens in a new tab)wai-bindgen-wasmtime (opens in a new tab)
CGuestwai-bindgen-gen-c (opens in a new tab)
JavaScriptHostwai-bindgen-gen-js (opens in a new tab)
PythonHost (Wasmer)wai-bindgen-gen-wasmer-py (opens in a new tab)
PythonHost (Wasmtime)wai-bindgen-gen-wasmtime-py (opens in a new tab)