Documentation
¶
Overview ¶
Package protocol provides a wire-protocol foundation for custom binary protocols: framed messages with versioned magic + sequence + opcode, encoding helpers (varint, quantised float), and a typed opcode registry where projects bind their per-opcode payload codecs.
Domain-agnostic; common applications:
- Custom UDP / TCP application protocols.
- Market-data feeds with fixed-shape per-tick messages.
- Sensor / IoT telemetry with bandwidth-constrained encodings.
- Cross-language protocols requiring byte-for-byte parity (the frame format is stable; golden vectors under kit/protocol/golden/ support cross-language parity testing — for example, against a matching C++ implementation in a paired client SDK).
Index ¶
- Variables
- func ReadQuantFloat(r *bytes.Reader, bits uint8) (float32, error)
- func ReadVarUint(r *bytes.Reader) (uint64, error)
- func Register[T any](r *Registry, op Opcode, name string, enc func(T, *bytes.Buffer), ...)
- func WriteQuantFloat(buf *bytes.Buffer, f float32, bits uint8)
- func WriteVarUint(buf *bytes.Buffer, v uint64)
- type Codec
- type Frame
- type Opcode
- type ReaderPool
- type Registry
Constants ¶
This section is empty.
Variables ¶
var ErrUnknownOpcode = errors.New("protocol: unknown opcode")
ErrUnknownOpcode is returned when decoding a frame whose opcode has no registered codec.
Functions ¶
func ReadQuantFloat ¶
ReadQuantFloat reads a value previously written with WriteQuantFloat.
func ReadVarUint ¶
ReadVarUint reads an unsigned LEB128 varint.
func Register ¶
func Register[T any](r *Registry, op Opcode, name string, enc func(T, *bytes.Buffer), dec func(*bytes.Reader) (T, error))
Register binds typed encode + decode functions to an opcode. Name is used for diagnostics.
func WriteQuantFloat ¶
WriteQuantFloat writes f as a quantised value using bits ∈ {16, 32}. 32-bit is IEEE 754 raw; 16-bit is bfloat16 (top 16 bits of float32), chosen because both endpoints round-trip identically.
func WriteVarUint ¶
WriteVarUint emits v as an unsigned LEB128 varint. Matches the encoding used by Google protobuf wire format (and our C++ side).
Types ¶
type Codec ¶
type Codec struct {
// contains filtered or unexported fields
}
Codec encodes / decodes Frames against a fixed Magic + Version. Wrong magic or version on decode returns an error.
func (*Codec) Decode ¶
Decode reads a Frame from in. Consumes the entire remaining buffer as payload (caller controls outer framing for stream transports). The returned Frame.Payload is a freshly-allocated slice; callers that need zero-allocation should use DecodeInto.
func (*Codec) DecodeInto ¶
DecodeInto reads a Frame from in, reusing payloadBuf for the payload allocation. If payloadBuf has sufficient capacity, no allocation occurs; otherwise a new slice grows behind it. Pass nil to behave like Decode (allocates a fresh slice each call).
type Frame ¶
type Frame struct {
Magic [2]byte
Version uint8
Flags uint8
Seq uint32
Opcode Opcode
Payload []byte
}
Frame is the wire-level message: a 10-byte header followed by Payload.
bytes | field -------+---------- 0..1 | Magic (uint8 × 2, e.g. "FG") 2 | Version (uint8) 3 | Flags (uint8) 4..7 | Seq (uint32, little-endian) 8..9 | Opcode (uint16, little-endian) ... | Payload (Length implicit from outer frame size)
type ReaderPool ¶
type ReaderPool struct {
// contains filtered or unexported fields
}
ReaderPool pools *bytes.Reader instances so callers can decode many frames without allocating a new Reader per call. Pair with DecodeInto + a recycled payload buffer for fully zero-alloc decoding.
func NewReaderPool ¶
func NewReaderPool() *ReaderPool
NewReaderPool returns an empty pool. The pool is safe for concurrent use.
func (*ReaderPool) Get ¶
func (p *ReaderPool) Get(data []byte) *bytes.Reader
Get returns a Reader positioned over data. Always return it via Put.
func (*ReaderPool) Put ¶
func (p *ReaderPool) Put(r *bytes.Reader)
Put returns a Reader to the pool.
type Registry ¶
type Registry struct {
// contains filtered or unexported fields
}
Registry maps Opcodes to per-type encode/decode functions. Callers register their typed payload codecs via the generic Register helper.
func (*Registry) DecodePayload ¶
DecodePayload looks up the codec for op and decodes from payload bytes.
func (*Registry) EncodePayload ¶
EncodePayload looks up the codec for op and encodes v into a new buffer.