lib/ex_zstd/dctx.ex

defmodule ExZstd.DCtx do
  @moduledoc """
  Decompression context. To know more check out the `ExZstd` doc.
  """

  alias ExZstd.Dparam
  alias ExZstd.Nif

  defstruct []

  @opaque t() :: %__MODULE__{}

  @typep maybe(t, err) :: {:ok, t} | {:error, err}

  @doc """
  Creates a decompression context
  """
  @spec new() :: t()
  defdelegate new, to: Nif, as: :dctx_new

  @doc """
  Decompresses a chunk of data using the given context. If `:content_size_unknown` is returned stream decompression can be still attempted.

  Note: this functions reads the header to find out the size of the decompressed data. Only feed it trusted input!
  """
  @spec decompress!(t(), binary()) :: binary()
  defdelegate decompress!(dctx, data), to: Nif, as: :dctx_decompress!

  @doc """
  Identical to `decompress!`. Wraps the result in a maybe instead of raising.

  Note: this functions reads the header to find out the size of the decompressed data. Only feed it trusted input!
  """
  @spec decompress(t(), binary()) :: maybe(binary(), ExZstd.decompression_error())
  def decompress(dctx, binary) do
    {:ok, decompress!(dctx, binary)}
  rescue
    ExZstd.ContentSizeError -> {:error, :content_size_error}
    ExZstd.ContentSizeUnknown -> {:error, :content_size_unknown}
    error -> {:error, Exception.message(error)}
  end

  @doc """
  Gets the value of a parameter of a decompression context (dparam).
  See `ExZstd.Dparam` for more information.
  """

  @spec get_dparam(t(), Dparam.t()) :: integer()
  defdelegate get_dparam(dctx, dparam), to: Nif, as: :dctx_get_dparam

  @doc """
  Sets a parameter of a decompression context (dparam) to the given value.
  See `ExZstd.Dparam` for more information.
  """
  @spec set_dparam(t(), pos_integer(), integer()) :: t()
  defdelegate set_dparam(dctx, dparam, value), to: Nif, as: :dctx_set_dparam

  @doc """
  Resets the decompression context, interrupting any ongoing decompression and resetting the parameters to their default values.
  """

  @spec reset(t(), ExZstd.reset_directive()) :: t()
  defdelegate reset(cctx, reset_directive), to: Nif, as: :dctx_reset

  @doc """
  Loads a decompression dictionary inside the decompresson context.
  """
  @spec load_dictionary(t(), binary()) :: t()
  defdelegate load_dictionary(dctx, dictionary), to: Nif, as: :dctx_load_dictionary

  @doc """
  Decompresses multiple frames with streaming.
  """
  @spec decompress_stream!(t(), binary()) :: {non_neg_integer(), binary()}
  defdelegate decompress_stream!(dctx, data), to: Nif, as: :dctx_decompress_stream!

  @doc """
  Identical to `decompress_stream`. Wraps the result in a maybe instead of raising.
  """
  @spec decompress_stream(t(), binary()) ::
          {:ok, non_neg_integer(), binary()} | {:error, ExZstd.error()}
  def decompress_stream(dctx, data) do
    {missing_bytes, decompressed_data} = decompress_stream!(dctx, data)
    {:ok, missing_bytes, decompressed_data}
  rescue
    error -> {:error, Exception.message(error)}
  end
end