Exgit.PktLine (exgit v0.1.0)

Copy Markdown View Source

Git's pkt-line framing.

Each pkt-line is 4 ASCII hex bytes of length (including the length header itself) followed by the payload, with three sentinels:

  • 0000 — flush
  • 0001 — delim (protocol v2)
  • 0002 — response-end

encode/1 emits the framed bytes for a data payload; decode_stream/1 parses a concatenated pkt-line stream into {:data, bin} | :flush | :delim | :response_end tokens. Decoders never raise on malformed or truncated input — bad framing surfaces as an {:error, {:malformed_pkt_line, snippet}} value; see Exgit.PropertiesTest for the fuzz property.

Summary

Functions

Eagerly decode a concatenated pkt-line stream.

Lazily decode a concatenated pkt-line stream.

Frame a data payload as a pkt-line.

Types

decode_error()

@type decode_error() :: {:error, {:malformed_pkt_line, binary()}}

packet()

@type packet() :: {:data, binary()} | :flush | :delim | :response_end

Functions

decode_all(bytes)

@spec decode_all(binary()) :: [packet()] | decode_error()

Eagerly decode a concatenated pkt-line stream.

Returns the packet list, or {:error, {:malformed_pkt_line, snippet}} when the input contains bad or truncated framing. A malformed stream is rejected whole — packets decoded before the bad framing are discarded. Never raises on hostile bytes.

decode_stream(bytes)

@spec decode_stream(binary()) :: Enumerable.t()

Lazily decode a concatenated pkt-line stream.

Yields packet/0 tokens. On malformed or truncated input the stream yields a final {:error, {:malformed_pkt_line, snippet}} token — snippet is up to 40 bytes of the offending input — and halts. Never raises on hostile bytes.

delim()

@spec delim() :: binary()

encode(data)

@spec encode(iodata()) :: iolist()

Frame a data payload as a pkt-line.

Payloads are capped at 65516 bytes — git's LARGE_PACKET_MAX (65520) minus the 4-byte length header. Raises ArgumentError for oversized payloads: the length header is 4 hex digits, so silently encoding anything larger would corrupt the wire stream. Callers sending bulk data (e.g. sideband frames) must chunk it below the limit.

flush()

@spec flush() :: binary()

response_end()

@spec response_end() :: binary()