はじめに
wirespec はネットワークプロトコルのワイヤフォーマットを記述する DSL です。.wspecファイルから C / Rust のパーサ・シリアライザを生成します。ヒープ割り当てなし、可能な箇所ではゼロコピー、生成コードは -Wall -Wextra -Werror でクリーンにコンパイルできます。
インストール
Rust(edition 2024)が必要です。
git clone https://github.com/wirespec-lang/wirespec.git
cd wirespec
cargo build --release
# バイナリの場所: target/release/wirespec最初の .wspec ファイル
最もシンプルな実用例として、UDP データグラムヘッダを定義します。examples/net/udp.wspec を作成してください:
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 へのコンパイル
wirespec compile examples/net/udp.wspec -t c -o build/2 つのファイルが生成されます:
build/net_udp.h— 構造体定義と関数宣言build/net_udp.c— パース、シリアライズ、長さ計算の関数
Rust へのコンパイル
-t rust で Rust モジュールを生成できます:
wirespec compile examples/net/udp.wspec -t rust -o build/
# 生成物: build/net_udp.rs出力はヒープ割り当てなしの struct + parse / serialize 関数を含む自己完結型の .rs ファイルです。
生成コードの概要
生成されるヘッダのイメージ:
/* 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_BUFFER や WIRESPEC_ERR_CONSTRAINT 等のエラーコードを返します。*consumed に読み込んだバイト数が入ります。
_serialize(val, buf, cap, written) — 構造体をバイナリへエンコード。WIRESPEC_OK またはエラーコードを返します。*written に書き込んだバイト数が入ります。
_serialized_len(val) — _serialize が書き込むバイト数を返します。バッファサイズの事前計算に使います。
ビルドとテスト
runtime/wirespec_runtime.h をインクルードパスに含め、生成 .c とテストコードを一緒にコンパイルします:
cd build
gcc -Wall -Wextra -Werror -O2 -std=c11 -I../runtime \
-o test_udp net_udp.c test_net_udp.c && ./test_udp主要コンセプト
- プリミティブ型・バイト型・配列 —
u8、u16le、bits[4]、bytes[remaining]、[T; count]→ 言語ツアー - フレーム・カプセル — タグ付きユニオン (
frame) と TLV コンテナ (capsule) → 言語ツアー - ステートマシン — 型付き遷移・ガード・アクション付きのプロトコル状態 → ステートマシン
- モジュール・インポート —
module/importによる複数ファイル構成 → モジュール
次のステップ
言語ツアー で wirespec の機能を一通り確認できます。