Rexd.Delta (Rexd v1.0.0)

Copy Markdown View Source

A delta: the commands that rebuild a new binary from a basis, and its librsync wire encoding.

Commands are {:literal, bytes} (append bytes) and {:copy, offset, length} (append length bytes of the basis starting at offset). Deltas computed by compute/2 never contain two adjacent literals, never contain a copy that directly continues the previous copy, and never contain zero-length commands.

Wire format: u32 RS_DELTA_MAGIC (0x72730236), then one command per opcode byte, then an END byte (0x00). The opcode selects the command kind and the widths of its big-endian arguments; see lib/rexd/delta/prototab.ex, generated from librsync's prototab.c. Encoding follows librsync's emit.c: literals of 1..64 bytes carry their length in the opcode, longer literals and both copy arguments use the smallest width that fits.

decode/1 rejects what librsync's patcher treats as a corrupt stream: zero-length literal or copy commands, and arguments of 2^63 or more (librsync reads them as signed 64-bit integers). Whether copies fit the basis is checked by Rexd.patch/3, the first point where the basis is known.

Summary

Functions

Decodes a librsync delta.

Encodes the delta in librsync wire format. Zero-length commands are omitted.

The delta magic number.

Statistics computed from the commands of delta. The search counters are nil.

Types

command()

@type command() ::
  {:literal, binary()} | {:copy, non_neg_integer(), non_neg_integer()}

decode_error()

@type decode_error() ::
  :truncated_header
  | :truncated
  | :missing_end
  | :trailing_data
  | {:bad_magic, non_neg_integer()}
  | {:reserved_opcode, byte()}
  | {:zero_length, :literal | :copy}
  | {:argument_too_large, non_neg_integer()}

Reasons decode/1 can fail.

t()

@type t() :: %Rexd.Delta{commands: [command()]}

Functions

decode(bin)

@spec decode(binary()) :: {:ok, t()} | {:error, decode_error()}

Decodes a librsync delta.

encode(delta)

@spec encode(t()) :: iodata()

Encodes the delta in librsync wire format. Zero-length commands are omitted.

magic()

@spec magic() :: non_neg_integer()

The delta magic number.

stats(delta)

@spec stats(t()) :: Rexd.Delta.Stats.t()

Statistics computed from the commands of delta. The search counters are nil.

iex> Rexd.Delta.stats(%Rexd.Delta{commands: [{:literal, "abc"}, {:copy, 0, 10}]})
%Rexd.Delta.Stats{literal_bytes: 3, literal_commands: 1, copy_bytes: 10, copy_commands: 1}