defmodule Snappywrap do @moduledoc """ A pure Elixir library to wrap a binary as _uncompressed_ data in Snappy format. This library _does not_ provide compress/decompress functions, but only wraps the data in Snappy framing or block format that can be decompressed (decoded) by Snappy-compatible libraries. This library is mostly for testing and/or low performance situations where using NIFs such as [`snappyrex`](https://github.com/c2bw/snappyrex) is not required. """ @doc """ Wraps binary data in Snappy `framing` format. Returns `{:ok, wrapped}` when the input is within the supported Snappy size limit of `2^32 - 1` bytes, or `{:error, message}` when it is too large. This function only accepts binaries. Passing any other type raises a `FunctionClauseError`. """ @spec wrap_framed(binary) :: {:ok, binary} | {:error, String.t()} def wrap_framed(data) when is_binary(data), do: data |> maybe_encode(&Snappywrap.Framing.encode/1) @doc """ Wraps binary data in Snappy `block` format. Returns `{:ok, wrapped}` when the input is within the supported Snappy size limit of `2^32 - 1` bytes, or `{:error, message}` when it is too large. This function only accepts binaries. Passing any other type raises a `FunctionClauseError`. """ @spec wrap(binary) :: {:ok, binary} | {:error, String.t()} def wrap(data) when is_binary(data), do: data |> maybe_encode(&Snappywrap.Block.encode/1) defp maybe_encode(data, encode_fn) do data |> byte_size() |> validate_input_size() |> case do :ok -> {:ok, encode_fn.(data)} {:error, _message} = error -> error end end @doc false @spec validate_input_size(non_neg_integer()) :: :ok | {:error, String.t()} def validate_input_size(data_bytes) when is_integer(data_bytes) and data_bytes >= 0 do max_bytes = Snappywrap.Helper.input_max_bytes() case data_bytes do data_bytes when data_bytes > max_bytes -> {:error, "Input exceeds the maximum allowed size of #{max_bytes} bytes"} _ -> :ok end end end