itsy v0.0.2 Itsy.Binary

Link to this section Summary

Functions

Generate an encoding for the given power of 2 length character set

Get the number of characters needed for an encoding, in order to pad to a whole byte

Get the number of bits one character of an encoding will represent

Pack a list of integers, floats, or bitstrings into a bitstring

Unpack integers, floats, or bitstrings from a bitstring

Link to this section Types

Link to this type decode_options()
decode_options() :: [bits: boolean(), pad_chr: String.t()]
Link to this type decode_type()
decode_type() :: :integer | :float | :bitstring
Link to this type decoder()
decoder() :: decode_type() | (bitstring(), [encodable()] -> decode_type())
Link to this type encodable()
encodable() :: number() | bitstring()
Link to this type encode_options()
encode_options() :: [
  multiple: pos_integer(),
  pad_chr: String.t(),
  pad_bit: integer()
]
Link to this type encoder_options()
encoder_options() :: [
  encode: atom(),
  decode: atom(),
  private: boolean(),
  docs: boolean()
]
Link to this type endianness()
endianness() :: :big | :little | :native
Link to this type packing_options()
packing_options() :: [
  position: position(),
  into: bitstring(),
  endian: endianness(),
  reverse: boolean()
]
Link to this type position()
position() :: :high | :low
Link to this type signedness()
signedness() :: :unsigned | :signed
Link to this type unpacking_options()
unpacking_options() :: [
  position: position(),
  count: nil | non_neg_integer(),
  endian: endianness(),
  sign: signedness(),
  reverse: boolean(),
  decoder: decoder()
]

Link to this section Functions

Link to this macro encoder(charset, opts \\ []) (macro)
encoder(
  [{char :: String.t(), value :: non_neg_integer()}, ...],
  encoder_options()
) :: Macro.t()

Generate an encoding for the given power of 2 length character set.

The encoder will generate two functions encode/3 and decode/3. These functions will be used to encode data using your specified encoding scheme, and decode strings with that encoding. The naming of these functions can be changed by setting the :encode and :decode options.

By default the functions are made public (including documentation). They can be made private by setting the :private option to true. Optionally only the docs can be removed by setting :docs to false.

The generated documentation includes some doctests. To use these tests make sure the module is specified as a doctest in your test code. If you do not wish for these to be included in your tests (but still want the docs), then simply exclude (:except option) the two functions from your ExUnit.DocTest.doctests/2.

defmodule MyBase4 do
    require Itsy.Binary

    "ABCD"
    |> String.graphemes
    |> Enum.with_index
    |> Itsy.Binary.encoder
end

MyBase4.encode("hello") |> MyBase4.decode
Link to this function encoder_padding(count)
encoder_padding(pos_integer()) :: pos_integer()

Get the number of characters needed for an encoding, in order to pad to a whole byte.

This value can be given to the :multiples option when encoding, in order to obtain an encoding with the minimum amount of padding needed so it can be concatenated with other encoded data.

iex> Itsy.Binary.encoder_padding(1)
1

iex> Itsy.Binary.encoder_padding(2)
8

iex> Itsy.Binary.encoder_padding(4)
4

iex> Itsy.Binary.encoder_padding(8)
8

iex> Itsy.Binary.encoder_padding(16)
2

iex> Itsy.Binary.encoder_padding(:erlang.bsl(1, 1000))
1
Link to this function encoder_size(count)
encoder_size(pos_integer()) :: integer()

Get the number of bits one character of an encoding will represent.

iex> Itsy.Binary.encoder_size(1)
0

iex> Itsy.Binary.encoder_size(2)
1

iex> Itsy.Binary.encoder_size(4)
2

iex> Itsy.Binary.encoder_size(8)
3

iex> Itsy.Binary.encoder_size(16)
4

iex> Itsy.Binary.encoder_size(:erlang.bsl(1, 1000))
1000
Link to this function pack(values, size, opts \\ [])

Pack a list of integers, floats, or bitstrings into a bitstring.

The values can be packed into a pre-existing bitstring by setting the :into option to the desired destination.

The position in the bitstring the values are packed is determined by the :position option. A :high position will place them in the high-order bits, while a :low position will place them in the low-order bits. By default this is set to :low.

The list can be inserted in the same order or optionally in reverse order, when the :reverse option is set to true.

  • [position: :high, reverse: false] - most significant bit will be based on the first number in the list.
  • [position: :high, reverse: true] - most significant bit will be based on the last number in the list.
  • [position: :low, reverse: true] - least significant bit will be based on the first number in the list.
  • [position: :low, reverse: false] - least significant bit will be based on the last number in the list.

The byte order defaults to big endian, this can be overriden by setting the :endian option to a kind expected by bitstring parameters.

iex> Itsy.Binary.pack([0], 2)
<<0 :: 2>>

iex> Itsy.Binary.pack([0], 3)
<<0 :: 3>>

iex> Itsy.Binary.pack([], 2)
<<>>

iex> Itsy.Binary.pack([0, 0, 0, 0], 2)
<<0 :: 8>>

iex> Itsy.Binary.pack([1, 2, 3, 4], 2)
<<1 :: 2, 2 :: 2, 3 :: 2, 0 :: 2>>

iex> Itsy.Binary.pack([1, 2, 3, 4], 2, position: :high)
<<1 :: 2, 2 :: 2, 3 :: 2, 0 :: 2>>

iex> Itsy.Binary.pack([1, 2, 3, 4], 2, reverse: true)
<<0 :: 2, 3 :: 2, 2 :: 2, 1 :: 2>>

iex> Itsy.Binary.pack([1, 2, 3, 4], 2, position: :high, reverse: true)
<<0 :: 2, 3 :: 2, 2 :: 2, 1 :: 2>>

iex> Itsy.Binary.pack([1, 2, 3, 4000], 12, position: :high, reverse: true)
<<4000 :: 12, 3 :: 12, 2 :: 12, 1 :: 12>>

iex> Itsy.Binary.pack([1, 2, 3, 4], 3, into: "foo")
<<"foo", 1 :: 3, 2 :: 3, 3 :: 3, 4 :: 3>>

iex> Itsy.Binary.pack([1, 2, 3, 4], 3, into: "foo", reverse: true)
<<"foo", 4 :: 3, 3 :: 3, 2 :: 3, 1 :: 3>>

iex> Itsy.Binary.pack([1, 2, 3, 4], 3, into: "foo", position: :high)
<<1 :: 3, 2 :: 3, 3 :: 3, 4 :: 3, "foo">>

iex> Itsy.Binary.pack([1, 2, 3, 4], 3, into: "foo", position: :high, reverse: true)
<<4 :: 3, 3 :: 3, 2 :: 3, 1 :: 3, "foo">>

iex> Itsy.Binary.pack([1], 32, endian: :little)
<<1 :: 8, 0 :: 24>>

iex> Itsy.Binary.pack([1], 32)
<<0 :: 24, 1 :: 8>>

iex> Itsy.Binary.pack([0.5], 32)
<<63 :: 8, 0 :: 24>>

iex> Itsy.Binary.pack(["foo", "bar"], 24)
"foobar"

iex> Itsy.Binary.pack(["foo", "bar"], 8)
"fb"

iex> Itsy.Binary.pack(["foo", "bar"], 32)
<<"foo", 0 :: 8, "bar", 0 :: 8>>
Link to this function unpack(packed, size, opts \\ [])

Unpack integers, floats, or bitstrings from a bitstring.

The type of value to unpack is inferred by the :decoder. By default this option is set to :integer, but can be set to any of the other types, or a function that will return the type to be used for that value.

A certain number of values can be unpacked by setting the :count option.

The position in the bitstring the values are packed is determined by the :position option. A :high position will place them in the high-order bits, while a :low position will place them in the low-order bits. By default this is set to :low.

The list can be inserted in the same order or optionally in reverse order, when the :reverse option is set to true.

  • [position: :high, reverse: false] - most significant bit will be used in the first number in the list.
  • [position: :high, reverse: true] - most significant bit will be used in the last number in the list.
  • [position: :low, reverse: true] - least significant bit will be used in the first number in the list.
  • [position: :low, reverse: false] - least significant bit will be used in the last number in the list.

The byte order defaults to big endian, this can be overriden by setting the :endian option to a kind expected by bitstring parameters.

The signedness of the integers defaults to unsigned, this can be overriden by setting the :sign option to a kind expected by bitstring parameters.

iex> Itsy.Binary.unpack(<<0 :: 2>>, 2)
[0]

iex> Itsy.Binary.unpack(<<0 :: 3>>, 3)
[0]

iex> Itsy.Binary.unpack(<<>>, 2)
[]

iex> Itsy.Binary.unpack(<<0 :: 8>>, 2)
[0, 0, 0, 0]

iex> Itsy.Binary.unpack(<<1 :: 2, 2 :: 2, 3 :: 2, 0 :: 2>>, 2)
[1, 2, 3, 0]

iex> Itsy.Binary.unpack(<<1 :: 2, 2 :: 2, 3 :: 2, 0 :: 2>>, 2, position: :high)
[1, 2, 3, 0]

iex> Itsy.Binary.unpack(<<0 :: 2, 3 :: 2, 2 :: 2, 1 :: 2>>, 2, reverse: true)
[1, 2, 3, 0]

iex> Itsy.Binary.unpack(<<0 :: 2, 3 :: 2, 2 :: 2, 1 :: 2>>, 2, position: :high, reverse: true)
[1, 2, 3, 0]

iex> Itsy.Binary.unpack(<<4000 :: 12, 3 :: 12, 2 :: 12, 1 :: 12>>, 12, position: :high, reverse: true)
[1, 2, 3, 4000]

iex> Itsy.Binary.unpack(<<"foo", 1 :: 3, 2 :: 3, 3 :: 3, 4 :: 3>>, 3, count: 4)
[1, 2, 3, 4]

iex> Itsy.Binary.unpack(<<"foo", 4 :: 3, 3 :: 3, 2 :: 3, 1 :: 3>>, 3, count: 4, reverse: true)
[1, 2, 3, 4]

iex> Itsy.Binary.unpack(<<1 :: 3, 2 :: 3, 3 :: 3, 4 :: 3, "foo">>, 3, count: 4, position: :high)
[1, 2, 3, 4]

iex> Itsy.Binary.unpack(<<4 :: 3, 3 :: 3, 2 :: 3, 1 :: 3, "foo">>, 3, count: 4, position: :high, reverse: true)
[1, 2, 3, 4]

iex> Itsy.Binary.unpack(<<1 :: 8, 0 :: 24>>, 32, endian: :little)
[1]

iex> Itsy.Binary.unpack(<<0 :: 24, 1 :: 8>>, 32)
[1]

iex> Itsy.Binary.unpack(<<255 :: 8>>, 8, endian: :big, sign: :signed)
[-1]

iex> Itsy.Binary.unpack(<<63 :: 8, 0 :: 24>>, 32, decoder: :float)
[0.5]

iex> Itsy.Binary.unpack("foobar", 24, decoder: :bitstring)
["foo", "bar"]

iex> Itsy.Binary.unpack(<<"test", 1 :: 32>>, 32, decoder: fn
...>     _, [] -> :bitstring
...>     _, _ -> :integer
...> end)
["test", 1]