The Wasm Interface Type text format
The Wasm Interface Type text format (WIT) is an Interface Description Language (IDL)—a language that facilitates communication between programs or objects created in different languages. IDL definitions are agnostic, or language-independent, working as intermediaries between two or more programming languages.
The WIT format is intended to be legible for humans, and to complement the WebAssembly component model. A basic tenet behind WIT is that it should be easy to read and write for developers.
The aim of the creators of WIT is to provide a foundation for producing components from guest programming languages. These components should then be usable by host programming languages.
Keywords
WIT uses the following keywords:
keyword | explanation |
---|---|
export | Makes an item accessible from host language. |
func | Function, read more |
import | Defines component requirement; Imports must be passed through constructor when components are instantiated. |
interface | Collection of functions and types, read more |
package | Collection of one or more .wit files, or units of WIT code, with an identifying ID, read more |
static | Function declaration for functions without implicit self parameters |
type | Type declaration, read more |
union | Variant type, where all variant entries have a type payload |
use | Defines import in interface. |
variant | Type containing a list of valid types; An item typed as a variant must match one of the listed variant types. |
world | Collection of exports and/or imports |
WIT supports a greater range of types than Wasm code. For a list of types, have a look at the following section.
You can read more about WIT in the WebAssembly component model repository on Github, here, or continue on to read our summary of the WIT building blocks.
WIT types
WIT supports the following predefined types:
type | explanation |
---|---|
bool | boolean |
char | character |
enum | enumerator |
flags | bitset structure with named bits |
float32 | 32-bit floating point data |
float64 | 64-bit floating point data |
handle | resource reference, can be borrowed or owned * |
id | identifier |
list | collection of values |
option | option type (encapsulates optional value) |
record | record type (collection with fixed number of values/named fields) |
result | result type (holds a return value or error value) |
s8 | signed 8-bit integer |
s16 | signed 16-bit integer |
s32 | signed 32-bit integer |
s64 | signed 64-bit integer |
string | string |
tuple | tuple (collection with fixed number of (two) values) |
u8 | unsigned 8-bit integer |
u16 | unsigned 16-bit integer |
u32 | unsigned 32-bit integer |
u64 | unsigned 64-bit integer |
union | union type (compound of several possible types, where all entries have a typed payload) |
variant | variant type (compound of several possible types) |
* An owned handle will call the destructor for the resource it refers to, when dropped. A borrowed handle will not call the destructor.
WIT also allows for user defined types, examples of which can be seen below.
WIT packages
WIT text, or code, is organized into packages. Each package is represented by a directory, containing WIT code separated into files. WIT packages can contain interfaces and worlds.
Type definitions within a WIT package can be shared between files. Type definitions are most easily shared between files within the same package with a use
statement, but types may also be shared between packages, with the addition of an identifying package ID to the use statement.
Valid WIT package files have the file ending .wit
, and should be encoded as UTF-8.
Package membership is also defined within a file, in the following format:
package local:example
WIT interface declaration
Now, consider the following type interface, belonging to the previously defined package:
package local:example
interface my-types {
record a-record {
small-number: u32,
big-number: u64,
}
record another-record {
a-number: u32,
another-number: u32,
}
type some-number = u32
}
Import the types above within the same package like this:
package local:example
interface another-interface {
use my-types.{a-record, another-record, some-number}
}
Import the same types into a file belonging to another package by adding the package ID to the use statement:
package local:another-example
interface another-interface {
use local:example/my-types.{a-record, another-record, some-number}
}
The examples above include interface definitions. Keep reading for more information about these interfaces.
WIT interfaces
WIT is built around the interface format, and interface definitions sit at the top level of WebAssembly components. interface is a collection of functions and types. WIT interfaces make Wasm code available to external code, and work much as a more traditional instance of a Wasm module.
A WIT interface can be seen as a collection of functions, types and use statements. Like a Wasm module, a WIT interface defines exports and imports.
A WIT interface can be defined as:
interface my-interface {
// interface contents
}
Key features of WIT interfaces:
- functions
- resources
- types
WIT functions
In WIT, a function can be defined as:
my-function: func(param: string)
When examining this statement, we find that a function declaration starts off with a label, or name:
my-function:
After the label, we have the definition of the function itself. It starts off with the keyword func
, for “function”, and then gets to the definition of parameters:
func(param: string)
Note that parameters are typed, and that the typing used can be either pre-defined types, like string in the example above, or user-defined types.
WIT resources
A WIT resource is defined as an entity with a limited lifetime that can only be passed indirectly via handle values. The abstract resource type is used in interfaces for items that shouldn’t be copied by value. In WIT, resource statements can look something like:
resource my-resource
But a resource definition can also have a body, which enables statements like:
resource my-resource {
constructor(init: u32) // 0-1 constructors per resource
some-function: func(param: u32) // a resource definition can contain function definitions
}
WIT worlds
A WIT world can be said to describe the type of a component, and it sits at the top level of a WebAssembly component. Worlds describe components, and define named imports and exports. Worlds can be structured as either component interfaces, or functions.
A WIT world can be defined as:
world my-world {
import local:example/my-types
export local:example/my-types
}