TL;DR
WebAssembly Component のインタフェースを定義するための言語(IDL)。
仕組み
インタフェース(interface)
interface に続けてインタフェース名を書き、{ と } の間に関数とデータ型を書く。関数は 関数名: func(引数リスト) -> 戻り値の型; の形で書く。
interface greetable {
name: func() -> string;
greet: func(name: string) -> string;
}ワールド(world)
コンポーネントの定義は world キーワードで書き、ワールドと呼ぶ。export には、コンポーネントが実装して外部に提供するインタフェースを、いくつでも書ける。import には、コンポーネントが依存する、外部で実装されたインタフェースを書く。
world greetable-provider {
import sayable;
export greetable;
}複数のインタフェースを export するコンポーネントは、各インタフェースを実装したコンポーネントを内部に持つ。インスタンス化すると内部のコンポーネントもインスタンス化されるので、インスタンスは他のインスタンスへの参照を持つ。
パッケージ(package)
パッケージは、ワールドやインタフェースの識別子になる。WIT ファイルの先頭で package ネームスペース:パッケージ ID の形で宣言する。ネームスペースは wa.dev などのレジストリのユーザ名や組織名である。
package radish:greet;
interface greetable {
name: func() -> string;
greet: func(name: string) -> string;
}
world greetable-provider {
export greetable;
}インタフェースやワールドの識別子は ネームスペース:パッケージ ID/名前 の形で、上の例では radish:greet/greetable になる。同じパッケージのインタフェースはネームスペースとパッケージ ID を省略できる。別のパッケージのものは省略できず、レジストリへの登録が必要である。
データ型
整数型は符号なしの u8〜u64 と符号ありの s8〜s64 で、Rust の u8〜u64、i8〜i64 に対応する。ほかに bool、f32、f64、char、string、list<T>、option<T>、result<T, E>、tuple<A, B> がある。
型を組み合わせるには、次のキーワードを使う。
enum: 値を持たない列挙型。Rust のenumに対応するvariant: 値を持てる列挙型。Rust のenumに対応するrecord: 構造体。Rust のstructに対応するflags: 複数の真偽値を名前付きでまとめるtype: 型エイリアスを定義するresource: ファイルなど、コンポーネントの外にあるリソースを操作するハンドル。状態を持ち、操作をメソッドとして定義できる
variant allowed-destinations {
none,
any,
restricted(list<address>),
}
record customer {
id: u64,
name: string,
picture: option<list<u8>>,
account-manager: employee,
}
type buffer = list<u8>;例
wasi:http の outgoing-request は resource で定義されている(抜粋)。詳しくは 第7章 Hello, wasi:http/proxy で扱っている。
resource outgoing-request {
constructor(headers: headers);
body: func() -> result<outgoing-body>;
method: func() -> method;
set-method: func(method: method) -> result;
headers: func() -> headers;
}自分の理解
コンポーネントは入れ子のような構造になっている、と捉えている。