Messages
Messages are the primary data type in Vexil -- ordered, typed fields with explicit ordinals.
message SensorReading {
channel @0 : u4
kind @1 : SensorKind
value @2 : u16
sequence @3 : u32 @varint
}
Fields are encoded in ordinal order. Each field has a name, an ordinal (@N), and a type.
Field ordinals
Ordinals determine wire order. They must be unique within a message but don't need to be sequential. Gaps are allowed -- this is important for schema evolution, since you can add new fields at new ordinals without disturbing existing ones.
message Config {
name @0 : string
# @1 was removed
timeout @2 : u32
retries @3 : u8
}
Field annotations
Fields can carry encoding annotations:
message Packet {
sequence @0 : u32 @varint # LEB128 variable-length encoding
delta @1 : i32 @zigzag # ZigZag encoding for signed values
payload @2 : bytes
}
Wire encoding
Fields are packed in ordinal order with LSB-first bit packing. Sub-byte fields (like u4) pack tightly -- two u4 fields occupy a single byte. After all fields, the encoder flushes to a byte boundary.
Unknown fields
Every generated message struct has an _unknown field that captures trailing bytes from newer schema versions. When a v1 decoder reads v2-encoded data, the extra bytes are preserved. Re-encoding includes them, enabling forward-compatible round-tripping with no data loss.
See the language specification for the full normative reference.