ReedSolomonEx (reed_solomon_ex v0.2.0)

View Source

Reed-Solomon encoder/decoder wrapper using Rust NIF.

Wraps the reed-solomon Rust crate to provide robust error-correcting codes for binary data. This library is suitable for transmitting binary packets over noisy links with optional parity.

Examples

iex> {:ok, codeword} = ReedSolomonEx.encode("hello", 4)
iex> {:ok, original} = ReedSolomonEx.correct(codeword, 4)
iex> original == "hello"
true

Schedulers

Codewords are capped at 255 bytes (GF(2^8)), so a single encode or decode is far below the ~1ms threshold that warrants a dirty scheduler. Encoding always runs on a regular scheduler; decoding runs on a regular scheduler for parity sizes up to 32 bytes and falls back to a dirty-CPU scheduler above that, where worst-case decode work on slow cores may exceed 1ms.

This matters on targets where the dirty-CPU run queue is kept busy by other NIFs (e.g. ML inference): a sub-millisecond encode should not queue behind a 100ms+ dirty job.

For many small chunks, prefer encode_batch/3 / correct_batch/3, which amortize NIF call overhead by looping in Rust. The wrapper slices large batches so no single regular-scheduler call exceeds the ~1ms budget.

Summary

Functions

Decode/correct a binary codeword and attempts to correct up to N/2 errors.

Decodes/corrects a list of codewords in a single NIF call per slice.

Decode/Correct a binary codeword and attempts to correct up to N/2 errors. Same as correct/2, but returns the number of errors corrected.

Encodes a binary by appending N parity bytes for error correction.

Encodes a list of binaries in a single NIF call per slice, appending parity_bytes of parity to each chunk.

Encodes a binary by appending N parity bytes for error correction. As encode/2, except that it only returns the parity bytes.

Check if a given codeword is corrupted (detectable by RS).

Functions

correct(codeword, parity_bytes, known_erasures)

@spec correct(binary(), non_neg_integer(), [byte()] | nil) ::
  {:ok, binary()} | {:error, any()}

Decode/correct a binary codeword and attempts to correct up to N/2 errors.

Runs on a regular scheduler for parity_bytes <= 32, on a dirty-CPU scheduler above that.

Parameters

  • codeword: binary of data + parity
  • parity_bytes: number of parity bytes originally used
  • known_erasures: offsets of known erasures (optional)

Returns

  • {:ok, original_data} on success
  • {:error, reason} if the message cannot be corrected

correct_batch(codewords, parity_bytes, opts \\ [])

@spec correct_batch([binary()], non_neg_integer(), keyword()) ::
  {:ok, [{:ok, binary()} | :error]}

Decodes/corrects a list of codewords in a single NIF call per slice.

Unlike encode_batch/3, failures are per-codeword: a corrupted-beyond-repair codeword yields :error in its position without failing the batch.

Known erasures are not supported in batch mode; use correct/3 for codewords with known erasure positions.

Parameters

  • codewords: list of binaries (data + parity each)
  • parity_bytes: number of parity bytes originally used
  • opts: slice_size: pos_integer() — codewords per NIF invocation

Returns

  • {:ok, results} where results is a list of {:ok, binary()} | :error, in input order

correct_err_count(codeword, parity_bytes, known_erasures)

@spec correct_err_count(binary(), non_neg_integer(), [byte()] | nil) ::
  {:ok, {binary(), non_neg_integer()}} | {:error, any()}

Decode/Correct a binary codeword and attempts to correct up to N/2 errors. Same as correct/2, but returns the number of errors corrected.

Runs on a regular scheduler for parity_bytes <= 32, on a dirty-CPU scheduler above that.

Parameters

  • codeword: binary of data + parity
  • parity_bytes: number of parity bytes originally used
  • known_erasures: offsets of known erasures (optional)

Returns

  • {:ok, {original_data, err_count}} on success
  • {:error, reason} if the message cannot be corrected

encode(data, parity_bytes)

@spec encode(binary(), non_neg_integer()) :: {:ok, binary()} | {:error, any()}

Encodes a binary by appending N parity bytes for error correction.

Runs on a regular scheduler: input is capped at 255 bytes total, so the work is always sub-millisecond.

Parameters

  • data: binary to encode
  • parity_bytes: number of bytes to use as parity (must be >= 2)

Returns

  • {:ok, binary} with appended parity
  • {:error, reason} on failure

encode_batch(chunks, parity_bytes, opts \\ [])

@spec encode_batch([binary()], non_neg_integer(), keyword()) ::
  {:ok, [binary()]} | {:error, any()}

Encodes a list of binaries in a single NIF call per slice, appending parity_bytes of parity to each chunk.

Equivalent to Enum.map(chunks, &encode(&1, parity_bytes)) but far cheaper when encoding many small chunks: one NIF round-trip covers a whole slice of chunks and the Reed-Solomon generator polynomial is computed once.

The chunk list is internally sliced so that no single NIF invocation exceeds the ~1ms regular-scheduler budget, even on slow cores. The slice size scales inversely with parity_bytes (32 chunks per call at parity 8) and can be overridden with the :slice_size option.

Parameters

  • chunks: list of binaries to encode (each byte_size(chunk) + parity_bytes <= 255)
  • parity_bytes: number of bytes to use as parity (must be >= 2)
  • opts: slice_size: pos_integer() — chunks per NIF invocation

Returns

  • {:ok, [binary()]} encoded codewords, in input order
  • {:error, reason} if any chunk is oversized (reports the failing chunk index)

encode_ecc(data, parity_bytes)

@spec encode_ecc(binary(), non_neg_integer()) :: {:ok, binary()} | {:error, any()}

Encodes a binary by appending N parity bytes for error correction. As encode/2, except that it only returns the parity bytes.

is_corrupted(codeword, parity_bytes)

@spec is_corrupted(binary(), non_neg_integer()) :: {:ok, boolean()} | {:error, any()}

Check if a given codeword is corrupted (detectable by RS).