Skip to main content

Module packstream

Module packstream 

Source
Expand description

PackStream — Bolt’s value encoding — and Bolt’s message chunking.

Hand-written because the whole codec is ~300 lines and the property that matters most is one no published crate states: a peer cannot make the decoder recurse without bound or allocate what the bytes do not contain. Two guards carry that:

  1. Depth. Lists, maps and structures nest, and one marker byte opens a level (0x91 is a one-element list), so ~1 KB on the wire buys a thousand frames of recursion. decode recurses with an explicit counter and refuses past MAX_PACKSTREAM_DEPTH. Real Bolt traffic nests three or four deep (a RUN’s parameter map holding a list of maps).
  2. Declared lengths. A 0xD6 list header declares a 32-bit element count in four bytes. Every count and byte length is checked against the bytes remaining before anything is allocated: an element needs at least one byte, a map entry at least two, so a count larger than that is refused as DecodeError::DeclaredLengthExceedsInput and Vec::with_capacity is only ever asked for what could actually be present.

Chunking (Dechunker) carries the third bound: a message is the concatenation of chunks (each a 2-byte big-endian size and that many bytes) ended by a zero-size chunk, and the total is capped at MAX_MESSAGE_BYTES as chunks arrive, so a peer that never sends the terminating zero cannot grow the buffer past it.

Encoding always picks the smallest form: integers in -16..=127 are one byte, strings under 16 bytes use the tiny marker, and so on. What NetGet encodes is either something it decoded (so already depth-bounded) or a JSON value the model wrote, which bolt::values bounds to the same depth before building it.

Structs§

Dechunker
Reassembles chunked messages from a byte stream, enforcing MAX_MESSAGE_BYTES as chunks arrive.

Enums§

DecodeError
Why a byte sequence is not a PackStream value.
FrameError
Why the byte stream is not a sequence of acceptable messages.
Value
A PackStream value.

Constants§

MAX_CHUNK_BYTES
The largest payload one chunk can carry (its size field is a u16).
MAX_MESSAGE_BYTES
Largest message, summed over its chunks, the server accepts. Neo4j imposes no fixed limit of its own; 1 MiB is several thousand times what cypher-shell sends for an interactive query and still room for a RUN carrying a sizeable parameter map.
MAX_PACKSTREAM_DEPTH
Deepest nesting of lists, maps and structures the decoder accepts. A message’s own top-level structure is depth 1, its fields depth 2, and so on.

Functions§

chunk
Frame one encoded message as chunks of at most MAX_CHUNK_BYTES, ended by 00 00.
decode
Decode exactly one value occupying the whole of bytes.
encode
Encode one value, choosing the smallest representation.
message_bytes
Encode a value and frame it as one chunked message.
to_bytes
Encode to a fresh buffer.