datastream/binary

Framing operations on Stream(BitArray).

Real byte sources (sockets, files, pipes) deliver bytes in arbitrary chunks. A frame may straddle chunks, several frames may sit in one chunk, or a chunk may end mid-prefix. Every framing combinator here owns the buffer needed to reassemble.

All combinators are lazy and chunk-boundary-aware; none of them materialises the full input.

Types

Truncation surfaced by length_prefixed when the input ends mid-frame.

expected is the number of bytes the combinator was waiting for — either prefix_size (when the prefix itself was short) or the declared payload length (when the prefix was complete but the payload was short). got is the number of bytes the stream actually delivered toward that requirement (always < expected).

pub type IncompleteFrame {
  IncompleteFrame(expected: Int, got: Int)
}

Constructors

  • IncompleteFrame(expected: Int, got: Int)

Values

pub fn bytes(
  over stream: datastream.Stream(BitArray),
) -> datastream.Stream(Int)

Yield each byte of each chunk in order, as Int in 0..255.

The trivial degenerate framing: bridges from Stream(BitArray) to Stream(Int) so callers can move into the byte-stream-shaped world without writing the per-byte unfold themselves.

pub fn delimited(
  over stream: datastream.Stream(BitArray),
  on delimiter: BitArray,
) -> datastream.Stream(BitArray)

Yield delimiter-separated frames in source order, preserving empty frames between consecutive delimiters and the trailing frame after a trailing delimiter. The delimiter itself is NOT included in any emitted frame.

If the input does not end with a delimiter, the trailing partial frame is emitted as the last element.

pub fn fixed_size(
  over stream: datastream.Stream(BitArray),
  size size: Int,
) -> datastream.Stream(BitArray)

Yield successive size-byte frames in source order. The trailing partial frame on EOF is discarded — by definition a fixed-size framing combinator cannot emit a frame of fewer than size bytes.

size MUST be >= 1. Other values are rejected at construction time with a panic per the datastream module-level invalid-argument policy.

pub fn length_prefixed(
  over stream: datastream.Stream(BitArray),
  prefix_size prefix_size: Int,
) -> datastream.Stream(Result(BitArray, IncompleteFrame))

Read a prefix_size byte big-endian unsigned length, then yield the next length bytes as a frame, wrapped in Ok.

prefix_size MUST be one of {1, 2, 4, 8}. Other values are rejected at construction time with a panic per the datastream module-level invalid-argument policy.

If the input ends mid-frame (the prefix is shorter than prefix_size bytes, or the payload is shorter than the declared length), the stream emits exactly one Error(IncompleteFrame(expected:, got:)) element before halting, so callers can distinguish “no more frames” from “truncated final frame”. The Stream(Result(_, _)) shape mirrors text.utf8_decode; chain fold.collect_result to stop on the first truncation, or fold.partition_result to drive the stream to completion and split well-formed frames from the incomplete tail.

Search Document