Binary-codec behaviour and shared catalog metadata.
Binary-interface modules registered with ExCodecs.CodecRegistry implement
this module's encode/2 and decode/2 callbacks on binaries. Spatial
entries share the catalog metadata struct but use the specialized
ExCodecs.Spatial contract because they map domain structs↔formats.
The %ExCodecs.Codec{} struct describes any shared-catalog entry. Its fields
are:
name(atom()) — registry key, such as:zstdcategory(atom()) — codec category, such as:compressionor:spatialinterface(:binary | :spatial) — public API shape used by the entrymodule(module() | nil) — implementation module, ornilwhen the codec is known but unavailablenative?(boolean() | nil) — whether the implementation uses a NIFstreaming?(boolean() | nil) — whether an incremental API is availableconfigurable?(boolean() | nil) — whether the codec accepts meaningful optionsversion(String.t() | nil) — backend version, if reported
Boolean capability fields and version may be nil on a bare %ExCodecs.Codec{}
until filled by __codec_info__/0 and/or ExCodecs.CodecRegistry.register/5.
For example:
iex> {:ok, %ExCodecs.Codec{} = codec} = ExCodecs.codec_info(:zstd)
iex> {codec.name, codec.category, codec.module}
{:zstd, :compression, ExCodecs.Compression.Zstd}Implementing a codec
defmodule ExCodecs.Compression.Zstd do
@behaviour ExCodecs.Codec
@impl true
def encode(data, opts) when is_binary(data) and is_list(opts) do
# ...
end
@impl true
def decode(data, opts) when is_binary(data) and is_list(opts) do
# ...
end
@impl true
def __codec_info__ do
%ExCodecs.Codec{
name: :zstd,
category: :compression,
module: __MODULE__,
native?: true,
streaming?: false,
configurable?: true,
version: "structured-zstd-0.0.48"
}
end
end
Summary
Types
Result returned by decode/2.
Result returned by encode/2.
Metadata for one shared codec-catalog entry.
Callbacks
Returns catalog metadata for this codec module.
Decodes binary data (decompress, etc.).
Encodes binary data (compress, hash, etc.).
Functions
Returns whether module exports encode/2 and decode/2.
Types
@type decode_result() :: {:ok, binary()} | {:error, ExCodecs.Error.t()}
Result returned by decode/2.
{:ok, decoded} contains the decoded binary. {:error, error} contains an
ExCodecs.Error whose reason is normally :invalid_data,
:invalid_options, :decompression_failed, :truncated_input, or
:nif_not_loaded.
Example
Requires the NIF to be loaded.
iex> {:ok, encoded} = ExCodecs.Compression.Zstd.encode("codec input", [])
iex> ExCodecs.Compression.Zstd.decode(encoded, [])
{:ok, "codec input"}
@type encode_result() :: {:ok, binary()} | {:error, ExCodecs.Error.t()}
Result returned by encode/2.
{:ok, encoded} contains the encoded binary. {:error, error} contains an
ExCodecs.Error whose reason is normally :invalid_data, :invalid_options,
:compression_failed, or :nif_not_loaded.
Example
Requires the NIF to be loaded (Zstd is NIF-backed). On a host without the
NIF, use a pure-Elixir codec or ExCodecs.supports?(:zstd) to gate.
iex> {:ok, result} = ExCodecs.Compression.Zstd.encode("codec input", [])
iex> is_binary(result)
true
@type t() :: %ExCodecs.Codec{ category: atom(), configurable?: boolean() | nil, interface: :binary | :spatial, module: module() | nil, name: atom(), native?: boolean() | nil, streaming?: boolean() | nil, version: String.t() | nil }
Metadata for one shared codec-catalog entry.
Every field is public:
name— catalog atom; binary entries can be passed toExCodecs.encode/3andExCodecs.decode/3category— grouping atom used byExCodecs.CodecRegistry.codecs_by_category/1interface—:binaryfor the top-level registry API or:spatialforExCodecs.Spatialmodule— callback implementation, ornilfor an unavailable codecnative?— indicates NIF-backed operation, orniluntil knownstreaming?— indicates incremental processing support, orniluntil knownconfigurable?— indicates codec-specific option support, orniluntil knownversion— backend version string, ornilif unknown
Boolean capability fields default to nil on %ExCodecs.Codec{} and are
typically filled by __codec_info__/0 and/or registry registration. After
a successful register/5 or register_unavailable/3 they are usually
concrete booleans; nil means unknown / not yet filled.
Example
iex> {:ok, codec} = ExCodecs.codec_info(:zstd)
iex> %ExCodecs.Codec{name: :zstd, configurable?: configurable?} = codec
iex> is_boolean(configurable?)
true
Callbacks
@callback __codec_info__() :: t()
Returns catalog metadata for this codec module.
Optional. When exported, ExCodecs.CodecRegistry.register/5 reads capability
fields (native?, streaming?, configurable?, version) from the returned
struct unless the caller overrides them via the metadata keyword. Registry
arguments always supply name, category, interface, and module on the
stored entry.
Arguments
None.
Returns
An %ExCodecs.Codec{} whose capability fields describe this implementation.
Callers may leave name/category/interface unset when the registry fills
those from register/5 arguments.
Raises
Implementations should not raise for a normal metadata return. Any exception raised here propagates through registration.
Implementation example
defmodule ExCodecs.Compression.Zstd do
@behaviour ExCodecs.Codec
@impl true
def __codec_info__ do
%ExCodecs.Codec{
name: :zstd,
category: :compression,
module: __MODULE__,
native?: true,
streaming?: false,
configurable?: true,
version: "structured-zstd-0.0.48"
}
end
end
@callback decode(data :: binary(), opts :: keyword()) :: decode_result()
Decodes binary data (decompress, etc.).
Arguments
data(binary()) — encoded bytes to decodeopts(keyword()) — codec-specific decoding options
Returns
{:ok, binary()}— decoded bytes{:error, %ExCodecs.Error{reason: :invalid_data}}— input has the wrong type or shape{:error, %ExCodecs.Error{reason: :invalid_options}}— unsupported or invalid options{:error, %ExCodecs.Error{reason: :decompression_failed}}— malformed payload or backend decoding failure{:error, %ExCodecs.Error{reason: :truncated_input}}— incomplete input, when the implementation distinguishes it{:error, %ExCodecs.Error{reason: :nif_not_loaded}}— native library unavailable
Raises
Implementations must return an error tuple for malformed data, invalid
options, and expected backend failures. They may raise only for programmer
errors or unexpected runtime faults not represented by ExCodecs.Error.
Implementation example
defmodule Example.PrefixCodec do
@behaviour ExCodecs.Codec
@impl true
def encode(data, []) when is_binary(data), do: {:ok, <<"EX", data::binary>>}
def encode(data, _opts) when not is_binary(data) do
ExCodecs.Error.error(:invalid_data, codec: :prefix)
end
def encode(_data, _opts) do
ExCodecs.Error.error(:invalid_options, codec: :prefix)
end
@impl true
def decode(<<"EX", data::binary>>, []), do: {:ok, data}
def decode(data, _opts) when not is_binary(data) do
ExCodecs.Error.error(:invalid_data, codec: :prefix)
end
def decode(_data, []), do: ExCodecs.Error.error(:decompression_failed, codec: :prefix)
def decode(_data, _opts), do: ExCodecs.Error.error(:invalid_options, codec: :prefix)
end
@callback encode(data :: binary(), opts :: keyword()) :: encode_result()
Encodes binary data (compress, hash, etc.).
Arguments
data(binary()) — bytes to encodeopts(keyword()) — codec-specific options; implementations should validate every supported key and value
Returns
{:ok, binary()}— encoded bytes{:error, %ExCodecs.Error{reason: :invalid_data}}— invalid input{:error, %ExCodecs.Error{reason: :invalid_options}}— unsupported or invalid options{:error, %ExCodecs.Error{reason: :compression_failed}}— backend encoding failure{:error, %ExCodecs.Error{reason: :nif_not_loaded}}— native library unavailable
Raises
Implementations must return an error tuple for invalid data, invalid options,
and expected backend failures. They may raise only for programmer errors or
unexpected runtime faults not represented by ExCodecs.Error.
Implementation example
defmodule Example.ReverseCodec do
@behaviour ExCodecs.Codec
@impl true
def encode(data, opts) when is_binary(data) and opts == [] do
{:ok, String.reverse(data)}
end
def encode(data, _opts) when not is_binary(data) do
ExCodecs.Error.error(:invalid_data, codec: :reverse)
end
def encode(_data, _opts) do
ExCodecs.Error.error(:invalid_options, codec: :reverse)
end
@impl true
def decode(data, opts), do: encode(data, opts)
end
Functions
Returns whether module exports encode/2 and decode/2.
Despite the name, this checks interface conformance (the module implements the codec callbacks), not runtime data validation.
Arguments
module(module()) — module to load and inspect
Returns
true—moduleloads and exports bothencode/2anddecode/2false— it cannot be loaded or either callback is missing
Raises
Does not raise for a valid module() atom. Passing a value outside the
declared type may raise FunctionClauseError from the code-loading API.
Examples
iex> ExCodecs.Codec.validates?(ExCodecs.Compression.Zstd)
true
iex> ExCodecs.Codec.validates?(Nonexistent.Module)
false