アノテーション
アノテーションはコンパイラの動作をカスタマイズしたり、定義にメタデータを付与します。@ を先頭に付け、対象の定義の直前に記述します。
@endian
構文: @endian big または @endian little
モジュール内の全マルチバイトフィールドのデフォルトエンディアンを設定します。通常はファイルの先頭に記述します。
| 値 | 説明 |
|---|---|
big | ビッグエンディアン(ネットワークバイト順)。QUIC、IP、TCP のデフォルト。 |
little | リトルエンディアン。BLE、USB、PCIe で一般的。 |
フィールドごとのサフィックスは常にモジュールデフォルトに優先します。 u16be、u16le、u32be、u32le 等を使えば、モジュール設定によらずフィールド単位でエンディアンを指定できます。
例 — BLE ATT(examples/ble/att.wspec):
@endian little
module ble.att
type AttHandle = u16le
type Uuid16 = u16le
frame AttPdu = match opcode: u8 {
0x02 => ExchangeMtuReq { client_rx_mtu: u16le },
0x0a => ReadReq { handle: AttHandle },
0x0b => ReadRsp { value: bytes[remaining] },
# ...
}@endian little でモジュールのデフォルトを設定しています。u16le はフィールド単位の明示的な指定で、モジュールデフォルトと一致しますが可読性のために明記しています。
制約:
- 1 モジュールにつき
@endianは 1 つまで。 - 値は
bigかlittleのみ。 - 単一バイトフィールド(
u8、bit、N <= 8 のbits[N])には影響しない。 bit/bits[N]フィールドはビットグループのエンディアン規則に従ってパックされる(言語リファレンス -- ビットフィールド を参照)。
@strict
構文: type 定義に @strict
パース時に非正規エンコーディングを拒否します。@strict を付けると、パーサーがワイヤエンコーディングの最短表現チェックを行い、非正規の場合は WIRESPEC_ERR_NONCANONICAL を返します。
主に可変長整数型に適用します。値が複数のバイト幅でエンコードできる場合(例: 5 を 1 バイト形式ではなく 2 バイト QUIC VarInt でエンコードするなど)に有効です。
例 — QUIC VarInt(examples/quic/varint.wspec):
module quic.varint
@strict
type VarInt = {
prefix: bits[2],
value: match prefix {
0b00 => bits[6], # 1 バイトエンコーディング:値 0..=63
0b01 => bits[14], # 2 バイトエンコーディング:値 0..=16383
0b10 => bits[30], # 4 バイトエンコーディング:値 0..=1073741823
0b11 => bits[62], # 8 バイトエンコーディング:値 0..=4611686018427387903
},
}@strict を付けると、仕様上は有効でも 2 バイト形式(prefix = 0b01)での 5 のエンコードは拒否されます。RFC 9000 が正規(最小長)エンコーディングを要求しており、@strict がこれを強制します。
@strict なしの場合、有効な値にデコードできるエンコーディングはすべて受け入れられます。
制約:
- 可変長構造(
matchを使った計算型)を持つtype定義にのみ適用可能。 - 固定幅型に付けても効果なし。
- 1 つの型定義につき
@strictは 1 つまで。
@checksum(algorithm)
構文: packet、frame ブランチ、または capsule ブランチ内のフィールドに @checksum(algorithm)
フィールドレベルのアノテーションで、パース時のチェックサム検証とシリアライズ時の自動計算を有効にします。
サポートされているアルゴリズム:
| アルゴリズム | フィールド型 | 方法 |
|---|---|---|
internet | u16 | RFC 1071 one's complement sum |
crc32 | u32 | IEEE 802.3 CRC-32 |
crc32c | u32 | Castagnoli CRC-32C |
fletcher16 | u16 | RFC 1146 Fletcher-16 |
パース時の動作:
パースされた構造体全体(パケット/フレームブランチが消費した全バイト)に対してチェックサムを計算します。検証失敗時は WIRESPEC_ERR_CHECKSUM を返します。
シリアライズ時の動作:
- チェックサムフィールドをゼロクリア。
- シリアライズされた構造体全体に対してチェックサムを計算。
- 計算値をチェックサムフィールドの位置に書き戻す。
シリアライズ結果には常に有効なチェックサムが含まれます。
例 — IPv4 ヘッダチェックサム(examples/ip/ipv4.wspec):
module ip.v4
@endian big
packet IPv4Header {
version: bits[4],
ihl: bits[4],
dscp: bits[6],
ecn: bits[2],
total_length: u16,
identification: u16,
flags: bits[3],
fragment_offset: bits[13],
ttl: u8,
protocol: u8,
@checksum(internet)
header_checksum: u16,
src_addr: u32,
dst_addr: u32,
}制約:
packet/frame/capsuleブランチにつき@checksumは最大 1 つ。同一構造体に複数あるとコンパイルエラー。- フィールド型はアルゴリズムの要件と一致が必要(
internet/fletcher16はu16、crc32/crc32cはu32)。不一致はコンパイルエラー。 - チェックサムの対象は構造体全体(パケット/フレームブランチの全バイト)。TCP/UDP 疑似ヘッダのようなクロスレイヤーチェックサムは非対応。
@checksumはスカラー整数フィールドにのみ適用可能。bytes[...]や配列フィールドには使えません。
@max_len(N)
構文: 配列フィールドに @max_len(N)(N は正の整数リテラル)
対象フィールドのデフォルト配列キャパシティ(WIRESPEC_MAX_ARRAY_ELEMENTS、デフォルト 64)を N に上書きします。同じ構造体内の他の配列フィールドはグローバルデフォルトのままです。
パース時に要素数がキャパシティを超えると WIRESPEC_ERR_CAPACITY を返します。
例:
packet Foo {
count: u16,
items: [Item; count], # キャパシティ = WIRESPEC_MAX_ARRAY_ELEMENTS(64)
@max_len(1024)
large_items: [Item; count], # キャパシティ = 1024
}グローバルデフォルトの設定:
C コンパイラに -DWIRESPEC_MAX_ARRAY_ELEMENTS=128 を渡すと、@max_len 未指定の全フィールドのデフォルトを変更できます。
制約:
Nは正の整数リテラル。0 や負の値はコンパイルエラー。- 配列フィールド(
[T; expr])にのみ適用可能。非配列フィールドに付けるとコンパイルエラー。 - 1 フィールドにつき
@max_lenは 1 つまで。
@doc(string)
構文: 任意の定義に @doc("text")
型・パケット・フレーム・カプセル・フィールド・定数の定義にドキュメント文字列を付与します。文字列は IR に保持されますが、現時点では生成される C コードには反映されません。
例:
@doc("RFC 9000 Section 17 — Long Header Packet")
packet QuicLongHeader {
header_form: bits[1],
fixed_bit: bits[1],
# ...
}注: 将来的にドキュメントジェネレータや LSP がホバー表示や API ドキュメント生成に @doc 文字列を利用する予定です。アノテーション自体は現在パース・検証済みで、出力への統合は後続マイルストーンで行います。
制約:
- 引数はダブルクォートの文字列リテラルのみ。
- 1 定義につき
@docは 1 つまで。