protocol

package
v1.4.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Apr 19, 2026 License: Apache-2.0 Imports: 4 Imported by: 0

Documentation

Overview

Package protocol implements the RESP2 and RESP3 wire protocol framing used by the celeris native Redis driver.

The parser is allocation-frugal: simple strings, errors, and bulk strings are returned as slices that alias the Reader's internal input buffer. Callers that need to retain bytes past the next Reader.Feed or Reader.Next call must copy them. The aggregate types (Array, Set, Push, Map, Attr) draw their backing slices from small sync.Pools — call Reader.Release on a top-level Value to return those slices to the pool.

RESP2 types: +, -, :, $, *. RESP3 types add: _ (null), # (bool), , (double), ( (bignum), ! (blob error), = (verbatim), ~ (set), % (map), | (attribute), > (push).

Incremental parsing

Reader.Next returns ErrIncomplete when the buffered input does not yet hold a full frame. The read cursor is not advanced in this case, so the caller should feed more bytes and retry.

Large bulk strings

Bulk strings longer than [maxInlineBulk] are returned in a freshly allocated heap buffer rather than kept in the Reader's own buffer. This prevents pathological growth of the Reader buffer on occasional large values.

Index

Constants

View Source
const (
	// MaxBulkLen caps the advertised length of a single bulk/verbatim/blob
	// error frame. 512 MiB matches Redis's own proto-max-bulk-len ceiling.
	MaxBulkLen = 512 * 1024 * 1024
	// MaxArrayLen caps the advertised element count of an aggregate
	// (array/set/push/map/attr). Chosen generously — 128M elements would
	// already represent gigabytes of pointers.
	MaxArrayLen = 128 * 1024 * 1024
)

Variables

View Source
var ErrIncomplete = errors.New("celeris-redis-protocol: incomplete frame")

ErrIncomplete indicates the buffered input does not yet contain a full RESP frame. The Reader's cursor is not advanced.

View Source
var ErrProtocol = errors.New("celeris-redis-protocol: protocol error")

ErrProtocol indicates malformed RESP input.

View Source
var ErrProtocolOversizedArray = errors.New("celeris-redis-protocol: aggregate length exceeds maximum")

ErrProtocolOversizedArray indicates an aggregate header (array / set / push / map / attr) exceeds MaxArrayLen.

View Source
var ErrProtocolOversizedBulk = errors.New("celeris-redis-protocol: bulk length exceeds maximum")

ErrProtocolOversizedBulk indicates a bulk string length header exceeds MaxBulkLen. Hostile or corrupt servers can otherwise force the Reader buffer to grow without bound while waiting for payload bytes.

Functions

func ClearPooledFlags

func ClearPooledFlags(v *Value)

ClearPooledFlags marks v (and its nested Array/Map entries) as non-pooled. Callers that deep-copy a Value into heap-allocated slices must invoke this so a later Reader.Release cannot return heap slices into the Reader's sync.Pools (which would corrupt later parses).

Types

type KV

type KV struct {
	K, V Value
}

KV is a key-value pair inside a Map or Attribute value.

type Reader

type Reader struct {
	// contains filtered or unexported fields
}

Reader is a streaming RESP decoder. It owns an append-only buffer that callers extend via Reader.Feed. The zero value is ready for use.

func NewReader

func NewReader() *Reader

NewReader returns a ready-to-use Reader.

func (*Reader) Compact

func (r *Reader) Compact()

Compact discards already-parsed bytes. Aliased slices from previously returned Values become invalid after Compact.

func (*Reader) Feed

func (r *Reader) Feed(data []byte)

Feed appends data to the internal buffer.

func (*Reader) Next

func (r *Reader) Next() (Value, error)

Next parses one complete RESP value. On ErrIncomplete, the read cursor is left unchanged; the caller should Feed more bytes and retry.

func (*Reader) Release

func (r *Reader) Release(v Value)

Release returns any pooled slices attached to v back to the Reader's internal pools. Safe to call on values whose aggregate slices were not pool-sourced (fields are simply cleared).

func (*Reader) Reset

func (r *Reader) Reset()

Reset clears internal state while keeping buffers for reuse.

type Type

type Type uint8

Type tags a RESP value.

const (
	// TySimple is a RESP2/RESP3 simple string prefixed by '+'.
	TySimple Type = iota
	// TyError is a RESP2/RESP3 simple error prefixed by '-'.
	TyError
	// TyInt is a RESP2/RESP3 integer prefixed by ':'.
	TyInt
	// TyBulk is a RESP2/RESP3 bulk string prefixed by '$'.
	TyBulk
	// TyArray is a RESP2/RESP3 array prefixed by '*'.
	TyArray
	// TyNull is a RESP3 null ('_') or a RESP2 null-bulk/null-array ($-1/*-1).
	TyNull
	// TyBool is a RESP3 boolean prefixed by '#'.
	TyBool
	// TyDouble is a RESP3 double prefixed by ','.
	TyDouble
	// TyBigInt is a RESP3 big number prefixed by '('.
	TyBigInt
	// TyBlobErr is a RESP3 blob error prefixed by '!'.
	TyBlobErr
	// TyVerbatim is a RESP3 verbatim string prefixed by '='.
	TyVerbatim
	// TySet is a RESP3 set prefixed by '~'.
	TySet
	// TyMap is a RESP3 map prefixed by '%'.
	TyMap
	// TyAttr is a RESP3 attribute map prefixed by '|'.
	TyAttr
	// TyPush is a RESP3 push frame prefixed by '>'.
	TyPush
)

func (Type) String

func (t Type) String() string

String returns a short name for diagnostics.

type Value

type Value struct {
	Type  Type
	Str   []byte
	Int   int64
	Float float64
	Bool  bool
	BigN  []byte
	Array []Value
	Map   []KV
	// contains filtered or unexported fields
}

Value is one decoded RESP value. Depending on Type, different fields are populated.

  • Simple / Error / Bulk / Verbatim / BlobErr → Str (may alias the Reader's buffer; copy before next Feed/Next).
  • Int → Int.
  • Double → Float.
  • Bool → Bool.
  • BigInt → BigN (raw ASCII, alias of buffer).
  • Array / Set / Push → Array.
  • Map / Attr → Map.
  • Null → no field set.

type Writer

type Writer struct {
	// contains filtered or unexported fields
}

Writer serializes RESP2 command arrays suitable for any Redis server. Only the RESP2 array-of-bulk-strings "inline command" form is emitted — servers accept this even when negotiated to RESP3 for responses.

func NewWriter

func NewWriter() *Writer

NewWriter returns a Writer with a small pre-allocated buffer.

func NewWriterSize

func NewWriterSize(size int) *Writer

NewWriterSize returns a Writer with a pre-allocated buffer of at least size bytes. Use this for pipeline workloads where the total encoded size is known or estimable, to avoid repeated grow-copies.

func (*Writer) AppendCommand

func (w *Writer) AppendCommand(args ...string) []byte

AppendCommand appends one command to the buffer without resetting.

func (*Writer) AppendCommand1

func (w *Writer) AppendCommand1(a0 string) []byte

AppendCommand1 appends a 1-arg command without allocating a []string slice.

func (*Writer) AppendCommand2

func (w *Writer) AppendCommand2(a0, a1 string) []byte

AppendCommand2 appends a 2-arg command without allocating a []string slice.

func (*Writer) AppendCommand3

func (w *Writer) AppendCommand3(a0, a1, a2 string) []byte

AppendCommand3 appends a 3-arg command without allocating a []string slice.

func (*Writer) AppendCommand4

func (w *Writer) AppendCommand4(a0, a1, a2, a3 string) []byte

AppendCommand4 appends a 4-arg command without allocating a []string slice.

func (*Writer) AppendCommand5

func (w *Writer) AppendCommand5(a0, a1, a2, a3, a4 string) []byte

AppendCommand5 appends a 5-arg command without allocating a []string slice.

func (*Writer) AppendCommandBytes

func (w *Writer) AppendCommandBytes(args [][]byte) []byte

AppendCommandBytes appends one []byte command.

func (*Writer) Bytes

func (w *Writer) Bytes() []byte

Bytes returns the serialized bytes.

func (*Writer) Grow

func (w *Writer) Grow(n int)

Grow ensures the Writer's internal buffer has at least n bytes of unused capacity. If the buffer already has sufficient capacity, this is a no-op.

func (*Writer) Reset

func (w *Writer) Reset()

Reset empties the internal buffer without freeing it.

func (*Writer) WriteCommand

func (w *Writer) WriteCommand(args ...string) []byte

WriteCommand appends *N\r\n$len\r\nARG\r\n... for the given string args and returns the full internal buffer slice. Callers that issue several commands before flushing should call Writer.Reset between commands — or use Writer.AppendCommand to append a second command after the first.

func (*Writer) WriteCommandBytes

func (w *Writer) WriteCommandBytes(args [][]byte) []byte

WriteCommandBytes is the []byte variant, avoiding the string conversion.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL