Skip to content

はじめに

wirespec はネットワークプロトコルのワイヤフォーマットを記述する DSL です。.wspecファイルから C / Rust のパーサ・シリアライザを生成します。ヒープ割り当てなし、可能な箇所ではゼロコピー、生成コードは -Wall -Wextra -Werror でクリーンにコンパイルできます。

インストール

Rust(edition 2024)が必要です。

bash
git clone https://github.com/wirespec-lang/wirespec.git
cd wirespec
cargo build --release
# バイナリの場所: target/release/wirespec

最初の .wspec ファイル

最もシンプルな実用例として、UDP データグラムヘッダを定義します。examples/net/udp.wspec を作成してください:

wire
module net.udp
@endian big

packet UdpDatagram {
    src_port: u16,
    dst_port: u16,
    length: u16,
    checksum: u16,
    require length >= 8,
    data: bytes[length: length - 8],
}

この定義の内容:

  • u16 のヘッダフィールド 4 つ(@endian big でビッグエンディアン)
  • 実行時制約 require length >= 8(ヘッダ自体が 8 バイトなので)
  • 可変長ペイロード bytes[length: length - 8] — 入力バッファへのゼロコピースライス

ファイル拡張子

wirespec は .wspec をファイル拡張子として使用します。

C へのコンパイル

bash
wirespec compile examples/net/udp.wspec -t c -o build/

2 つのファイルが生成されます:

  • build/net_udp.h — 構造体定義と関数宣言
  • build/net_udp.c — パース、シリアライズ、長さ計算の関数

Rust へのコンパイル

-t rust で Rust モジュールを生成できます:

bash
wirespec compile examples/net/udp.wspec -t rust -o build/
# 生成物: build/net_udp.rs

出力はヒープ割り当てなしの struct + parse / serialize 関数を含む自己完結型の .rs ファイルです。

生成コードの概要

生成されるヘッダのイメージ:

c
/* Auto-generated by wirespec compiler -- DO NOT EDIT */
#ifndef WIRESPEC_NET_UDP_H
#define WIRESPEC_NET_UDP_H

#include <stdint.h>
#include <stddef.h>
#include <stdbool.h>

#include "wirespec_runtime.h"

typedef struct net_udp_udp_datagram net_udp_udp_datagram_t;

/* UdpDatagram */
struct net_udp_udp_datagram {
    uint16_t src_port;
    uint16_t dst_port;
    uint16_t length;
    uint16_t checksum;
    wirespec_bytes_t data;
};

wirespec_result_t net_udp_udp_datagram_parse(
    const uint8_t *buf, size_t len,
    net_udp_udp_datagram_t *out, size_t *consumed);

wirespec_result_t net_udp_udp_datagram_serialize(
    const net_udp_udp_datagram_t *val,
    uint8_t *buf, size_t cap, size_t *written);

size_t net_udp_udp_datagram_serialized_len(const net_udp_udp_datagram_t *val);

#endif /* WIRESPEC_NET_UDP_H */

wirespec_bytes_t{const uint8_t *ptr; size_t len;} で入力バッファへのビューを表現します。コピーも割り当てもしません。

生成される 3 つの関数

wirespec の型ごとに以下の 3 関数が生成されます:

_parse(buf, len, out, consumed) — バイナリから構造体へデコード。成功時は WIRESPEC_OK、失敗時は WIRESPEC_ERR_SHORT_BUFFERWIRESPEC_ERR_CONSTRAINT 等のエラーコードを返します。*consumed に読み込んだバイト数が入ります。

_serialize(val, buf, cap, written) — 構造体をバイナリへエンコード。WIRESPEC_OK またはエラーコードを返します。*written に書き込んだバイト数が入ります。

_serialized_len(val)_serialize が書き込むバイト数を返します。バッファサイズの事前計算に使います。

ビルドとテスト

runtime/wirespec_runtime.h をインクルードパスに含め、生成 .c とテストコードを一緒にコンパイルします:

bash
cd build
gcc -Wall -Wextra -Werror -O2 -std=c11 -I../runtime \
    -o test_udp net_udp.c test_net_udp.c && ./test_udp

主要コンセプト

  • プリミティブ型・バイト型・配列u8u16lebits[4]bytes[remaining][T; count]言語ツアー
  • フレーム・カプセル — タグ付きユニオン (frame) と TLV コンテナ (capsule) → 言語ツアー
  • ステートマシン — 型付き遷移・ガード・アクション付きのプロトコル状態 → ステートマシン
  • モジュール・インポートmodule / import による複数ファイル構成 → モジュール

次のステップ

言語ツアー で wirespec の機能を一通り確認できます。