wire / wire-format / protobuf-wire
Protobuf serializes a message as a stream of fields, each preceded by a varint 'tag' that packs the field number and a 3-bit wire type: tag = (field_number << 3) | wire_type. The wire type (0 varint, 1 64-bit, 2 length-delimited, 5 32-bit) tells the parser how to read the value, so unknown fields can be skipped. It is a tag-then-value scheme, a lean cousin of ASN.1 TLV.
aka: protobuf · protocol buffers · proto wire format · field tag
spec: Protocol Buffers Encoding (protobuf.dev)
Each field on the wire is a key (a varint tag) optionally followed by its value. The tag encodes both the field number and a wire type: tag = (field_number << 3) | wire_type. Wire type 0 = varint (int32/64, uint, bool, enum, sint via zigzag); 1 = 64-bit (fixed64, double); 2 = length-delimited (string, bytes, embedded messages, packed repeated) which is itself a length-then-value TLV; 5 = 32-bit (fixed32, float). Wire types 3/4 (start/end group) are deprecated.
| field | size | meaning |
|---|---|---|
| Tag (key) | 1+ bytes (varint) | (field_number << 3) | wire_type. Low 3 bits = wire type, the rest = field number. LEB128 varint, so large field numbers take more bytes. |
| Value | depends on wire type | wire type 0: a varint. type 1: exactly 8 bytes (little-endian). type 2: a varint length followed by that many content bytes (a nested TLV). type 5: exactly 4 bytes (little-endian). |
example:
08 96 01
Field #1 = 150. Tag 0x08 = (1<<3)|0 => field 1, wire type 0 (varint). Value 96 01 is the LEB128 varint for 150 (0x96 has continuation bit set: 0x16=22 low 7 bits; 0x01 high => 1*128 + 22 = 150).
agent: curl -H 'accept: application/json' wire.phall.io/wire-format/protobuf-wire
or /wire-format/protobuf-wire.json