Annotations
Annotations customize compiler behavior or attach metadata to definitions. They are prefixed with @ and appear before the definition they apply to.
@endian
Syntax: @endian big or @endian little
Sets the default endianness for all multi-byte fields in the module. Applies at module scope — typically placed at the top of the file.
| Value | Description |
|---|---|
big | Big-endian (network byte order). Default for QUIC, IP, TCP. |
little | Little-endian. Common for BLE, USB, PCIe. |
Per-field suffix always overrides the module default. Use u16be, u16le, u32be, u32le, etc. to force a specific endianness on individual fields regardless of the module setting.
Example — 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] },
# ...
}Here @endian little sets the module default. u16le fields are explicit per-field overrides (consistent with the module default, but explicit for clarity).
Constraints:
- One
@endiandeclaration per module. - Valid values are
bigandlittleonly. - Has no effect on single-byte fields (
u8,bit,bits[N]where N ≤ 8). - The
bitprimitive andbits[N]fields are always packed according to endianness rules for bit groups (see Language Reference — Bit Fields).
@strict
Syntax: @strict on a type definition
Rejects non-canonical encodings at parse time. When @strict is present, the parser checks that the wire encoding is the shortest possible representation. Non-canonical encodings cause the parse function to return WIRESPEC_ERR_NONCANONICAL.
This applies to variable-length integer types where a value may be legally encoded in multiple byte widths (e.g., encoding 5 as a 2-byte QUIC VarInt instead of the canonical 1-byte form).
Example — QUIC VarInt (examples/quic/varint.wspec):
module quic.varint
@strict
type VarInt = {
prefix: bits[2],
value: match prefix {
0b00 => bits[6], # 1-byte encoding: values 0..=63
0b01 => bits[14], # 2-byte encoding: values 0..=16383
0b10 => bits[30], # 4-byte encoding: values 0..=1073741823
0b11 => bits[62], # 8-byte encoding: values 0..=4611686018427387903
},
}With @strict, encoding 5 using the 2-byte form (prefix = 0b01) is rejected even though it is a valid encoding per the format spec. RFC 9000 requires canonical (minimum-length) encoding; @strict enforces this.
Without @strict, all encodings that decode to a valid value are accepted.
Constraints:
- Applies only to
typedefinitions with variable-length structure (computed types usingmatch). - Applying
@strictto a fixed-width type has no effect. - One
@strictper type definition.
@checksum(algorithm)
Syntax: @checksum(algorithm) on a field within a packet, frame branch, or capsule branch
Field-level annotation that enables automatic checksum verification on parse and automatic checksum computation on serialize.
Supported algorithms:
| Algorithm | Field Type | Method |
|---|---|---|
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 |
Behavior on parse:
The checksum is computed over the entire parsed struct (all bytes consumed by the packet/frame branch). If verification fails, the parse function returns WIRESPEC_ERR_CHECKSUM.
Behavior on serialize:
- The checksum field is zeroed.
- The checksum is computed over the entire serialized struct.
- The computed value is written back into the checksum field position.
The serialized output always contains a valid checksum.
Example — IPv4 header checksum (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,
}Constraints:
- At most one
@checksumannotation perpacketorframe/capsulebranch. Multiple checksum fields in the same struct is a compile error. - The field type must match the algorithm requirement (
u16forinternet/fletcher16,u32forcrc32/crc32c). Mismatched type is a compile error. - The checksum covers the entire struct (all bytes of the packet/frame branch). Cross-layer checksums such as TCP/UDP pseudo-headers are not supported.
- The
@checksumannotation cannot appear onbytes[...]fields or array fields — only on scalar integer fields.
@max_len(N)
Syntax: @max_len(N) on an array field, where N is a positive integer literal
Overrides the global default array capacity (WIRESPEC_MAX_ARRAY_ELEMENTS, default 64) for the annotated field. All other array fields in the struct continue to use the global default.
When the parsed element count exceeds the field's capacity, the parse function returns WIRESPEC_ERR_CAPACITY.
Example:
packet Foo {
count: u16,
items: [Item; count], # capacity = WIRESPEC_MAX_ARRAY_ELEMENTS (64)
@max_len(1024)
large_items: [Item; count], # capacity = 1024
}Setting the global default:
Pass -DWIRESPEC_MAX_ARRAY_ELEMENTS=128 to the C compiler to change the default for all fields without @max_len.
Constraints:
Nmust be a positive integer literal. Zero and negative values are compile errors.- Applies only to array fields (
[T; expr]). Applying to a non-array field is a compile error. - One
@max_lenper field.
@doc(string)
Syntax: @doc("text") on any definition
Attaches a documentation string to a type, packet, frame, capsule, field, or constant definition. The string is preserved in the IR but currently has no effect on generated C code.
Example:
@doc("RFC 9000 Section 17 — Long Header Packet")
packet QuicLongHeader {
header_form: bits[1],
fixed_bit: bits[1],
# ...
}Note: Future tooling (documentation generators, language server protocol) will use @doc strings for hover documentation and generated API docs. The annotation is parsed and validated today; integration with output is planned for a later milestone.
Constraints:
- The argument must be a string literal (double-quoted).
- One
@docper definition.