defmodule FDB.Coder.Integer do
@moduledoc """
Supports integer in the range
`-0xFFFFFFFFFFFFFFFF..0xFFFFFFFFFFFFFFFF` (8 bytes). Consider using
`FDB.Coder.ArbitraryInteger` for arbitrary precision numbers.
"""
use FDB.Coder.Behaviour
use Bitwise
@spec new() :: FDB.Coder.t()
def new do
%FDB.Coder{module: __MODULE__}
end
@impl true
def encode(n, _) when n in -0xFFFFFFFFFFFFFFFF..-0x0100000000000000,
do: <<0x0C>> <> complement(<<-n::integer-big-64>>)
def encode(n, _) when n in -0xFFFFFFFFFFFFFF..-0x01000000000000,
do: <<0x0D>> <> complement(<<-n::integer-big-56>>)
def encode(n, _) when n in -0xFFFFFFFFFFFF..-0x010000000000,
do: <<0x0E>> <> complement(<<-n::integer-big-48>>)
def encode(n, _) when n in -0xFFFFFFFFFF..-0x0100000000,
do: <<0x0F>> <> complement(<<-n::integer-big-40>>)
def encode(n, _) when n in -0xFFFFFFFF..-0x01000000,
do: <<0x10>> <> complement(<<-n::integer-big-32>>)
def encode(n, _) when n in -0xFFFFFF..-0x010000,
do: <<0x11>> <> complement(<<-n::integer-big-24>>)
def encode(n, _) when n in -0xFFFF..-0x0100,
do: <<0x12>> <> complement(<<-n::integer-big-16>>)
def encode(n, _) when n in -0xFF..-0x01, do: <<0x13>> <> complement(<<-n::integer-big-8>>)
def encode(n, _) when n == 0, do: <<0x14>>
def encode(n, _) when n in 0x01..0xFF, do: <<0x15>> <> <<n::integer-big-8>>
def encode(n, _) when n in 0x0100..0xFFFF, do: <<0x16>> <> <<n::integer-big-16>>
def encode(n, _) when n in 0x010000..0xFFFFFF, do: <<0x17>> <> <<n::integer-big-24>>
def encode(n, _) when n in 0x01000000..0xFFFFFFFF, do: <<0x18>> <> <<n::integer-big-32>>
def encode(n, _) when n in 0x0100000000..0xFFFFFFFFFF, do: <<0x19>> <> <<n::integer-big-40>>
def encode(n, _) when n in 0x010000000000..0xFFFFFFFFFFFF,
do: <<0x1A>> <> <<n::integer-big-48>>
def encode(n, _) when n in 0x01000000000000..0xFFFFFFFFFFFFFF,
do: <<0x1B>> <> <<n::integer-big-56>>
def encode(n, _) when n in 0x0100000000000000..0xFFFFFFFFFFFFFFFF,
do: <<0x1C>> <> <<n::integer-big-64>>
@impl true
def decode(<<0x0C>> <> rest, _) do
<<n::binary-size(8), rest::binary>> = rest
<<n::integer-big-64>> = complement(n)
{-n, rest}
end
def decode(<<0x0D>> <> rest, _) do
<<n::binary-size(7), rest::binary>> = rest
<<n::integer-big-56>> = complement(n)
{-n, rest}
end
def decode(<<0x0E>> <> rest, _) do
<<n::binary-size(6), rest::binary>> = rest
<<n::integer-big-48>> = complement(n)
{-n, rest}
end
def decode(<<0x0F>> <> rest, _) do
<<n::binary-size(5), rest::binary>> = rest
<<n::integer-big-40>> = complement(n)
{-n, rest}
end
def decode(<<0x10>> <> rest, _) do
<<n::binary-size(4), rest::binary>> = rest
<<n::integer-big-32>> = complement(n)
{-n, rest}
end
def decode(<<0x11>> <> rest, _) do
<<n::binary-size(3), rest::binary>> = rest
<<n::integer-big-24>> = complement(n)
{-n, rest}
end
def decode(<<0x12>> <> rest, _) do
<<n::binary-size(2), rest::binary>> = rest
<<n::integer-big-16>> = complement(n)
{-n, rest}
end
def decode(<<0x13>> <> rest, _) do
<<n::binary-size(1), rest::binary>> = rest
<<n::integer-big-8>> = complement(n)
{-n, rest}
end
def decode(<<0x14>> <> rest, _), do: {0, rest}
def decode(<<0x15>> <> rest, _) do
<<n::integer-big-8, rest::binary>> = rest
{n, rest}
end
def decode(<<0x16>> <> rest, _) do
<<n::integer-big-16, rest::binary>> = rest
{n, rest}
end
def decode(<<0x17>> <> rest, _) do
<<n::integer-big-24, rest::binary>> = rest
{n, rest}
end
def decode(<<0x18>> <> rest, _) do
<<n::integer-big-32, rest::binary>> = rest
{n, rest}
end
def decode(<<0x19>> <> rest, _) do
<<n::integer-big-40, rest::binary>> = rest
{n, rest}
end
def decode(<<0x1A>> <> rest, _) do
<<n::integer-big-48, rest::binary>> = rest
{n, rest}
end
def decode(<<0x1B>> <> rest, _) do
<<n::integer-big-56, rest::binary>> = rest
{n, rest}
end
def decode(<<0x1C>> <> rest, _) do
<<n::integer-big-64, rest::binary>> = rest
{n, rest}
end
defp complement(<<>>), do: <<>>
defp complement(<<n::integer-size(8), rest::binary>>) do
<<(~~~n)::integer-8, complement(rest)::binary>>
end
end