Open1
Zig comptime 実例集

@unionInit()
x inline else
バイナリデータを扱うコードではありがちな、「バイト列を指すポインタがあり、そのバイト列が表すデータ型はヘッダの値に応じて変わる」というパターン。判明したデータ型に応じて、そのバイト列を指すポインタを具体的なデータ型に変換する関数:
const DataType = enum(u8) { a, b, c };
const Data = union(DataType) {
a: *align(1) packed struct {...},
b: *align(1) packed struct {...},
c: *align(1) packed struct {...},
};
fn getData(bytes: [*]u8, data_type: DataType) Data {
return switch (data_type) {
inline else => |t| @unionInit(
Data,
@tagName(t),
@alignCast(@ptrCast(bytes)),
)
};
}
@unionInit()
は union
の初期化において、active なフィールドの指定をトークンではなく comptime
な文字列で行える。
inline else
と @tagName()
で全てのフィールドのタグ文字列に対し共通して union
の初期化ができる。愚直にやると全てのフィールドに対する case を列挙する必要があったり、もしくは inline for (std.meta.fields(DataType))
とする必要があるが、これならシンプル。
用例
- ACPI の MADT テーブルから要素を取得する時に出てきた: https://github.com/smallkirby/norn/commit/7047f3fbf59066812306d25c7a9c918376910be4