···11-defmodule Hobbes.Enc do
11+defmodule Hobbes.Encoding.Keyset do
22 @moduledoc """
33 Encodings for Hobbes keys and values.
44 """
···1818 @int_pos_7 0x1C
1919 @int_pos_8 0x1D
20202121- @spec encode_key(list) :: binary
2222- def encode_key(list) when is_list(list) do
2323- enc_key(list, 0)
2121+ @spec pack(list) :: binary
2222+ def pack(list) when is_list(list) do
2323+ encode(list, 0)
2424 |> IO.iodata_to_binary()
2525 end
26262727- @spec decode_key(binary) :: list
2828- def decode_key(binary) when is_binary(binary) do
2929- case dec_key(binary, 0) do
2727+ @spec unpack(binary) :: list
2828+ def unpack(binary) when is_binary(binary) do
2929+ case decode(binary, 0) do
3030 {values, ""} ->
3131 values
3232 end
3333 end
34343535- defp enc_key(nil, 0), do: <<@nil_value>>
3636- defp enc_key(nil, depth) when depth > 0, do: <<@nil_value, @escape>>
3535+ defp encode(nil, 0), do: <<@nil_value>>
3636+ defp encode(nil, depth) when depth > 0, do: <<@nil_value, @escape>>
37373838- defp enc_key(list, 0) when is_list(list) do
3939- Enum.map(list, &enc_key(&1, 1))
3838+ defp encode(list, 0) when is_list(list) do
3939+ Enum.map(list, &encode(&1, 1))
4040 end
41414242- defp enc_key(list, depth) when is_list(list) and depth > 0 do
4343- values = Enum.map(list, &enc_key(&1, depth + 1))
4242+ defp encode(list, depth) when is_list(list) and depth > 0 do
4343+ values = Enum.map(list, &encode(&1, depth + 1))
4444 [@nested_list, values, @nil_value]
4545 end
46464747- defp enc_key(binary, _depth) when is_binary(binary) do
4848- [<<@binary>>, enc_binary(binary, 0)]
4747+ defp encode(binary, _depth) when is_binary(binary) do
4848+ [<<@binary>>, encode_binary(binary, 0)]
4949 end
50505151- defp enc_key(0, _depth) do
5151+ defp encode(0, _depth) do
5252 <<@int_0>>
5353 end
54545555- defp enc_key(int, _depth) when is_integer(int) and int > 0 do
5555+ defp encode(int, _depth) when is_integer(int) and int > 0 do
5656 binary = :binary.encode_unsigned(int)
5757 case byte_size(binary) do
5858 1 -> [<<@int_pos_1>>, binary]
···6767 end
68686969 # Encodes a null-terminated binary, nulls are escaped as <<0x00, 0xFF>>
7070- defp enc_binary(binary, offset) do
7070+ defp encode_binary(binary, offset) do
7171 case binary do
7272 <<head::binary-size(offset)>> ->
7373 # Terminate encoded binary (null-terminated)
···75757676 <<head::binary-size(offset), 0x00, tail::binary>> ->
7777 # Escape null value in binary and keep going
7878- [head, <<@nil_value, @escape>> | enc_binary(tail, 0)]
7878+ [head, <<@nil_value, @escape>> | encode_binary(tail, 0)]
79798080 <<_head::binary-size(offset), _other, _tail::binary>> ->
8181 # Non-null character, keep scanning
8282- enc_binary(binary, offset + 1)
8282+ encode_binary(binary, offset + 1)
8383 end
8484 end
85858686- defp dec_key("", 0) do
8686+ defp decode("", 0) do
8787 {[], ""}
8888 end
89899090- defp dec_key(<<@nil_value, rest::binary>>, 0 = depth) do
9191- {values, tail} = dec_key(rest, depth)
9090+ defp decode(<<@nil_value, rest::binary>>, 0 = depth) do
9191+ {values, tail} = decode(rest, depth)
9292 {[nil | values], tail}
9393 end
94949595 # Escaped nil within a nested list
9696- defp dec_key(<<@nil_value, @escape, rest::binary>>, depth) when depth > 0 do
9797- {values, tail} = dec_key(rest, depth)
9696+ defp decode(<<@nil_value, @escape, rest::binary>>, depth) when depth > 0 do
9797+ {values, tail} = decode(rest, depth)
9898 {[nil | values], tail}
9999 end
100100101101 # Closing a nested list
102102- defp dec_key(<<@nil_value, rest::binary>>, depth) when depth > 0 do
102102+ defp decode(<<@nil_value, rest::binary>>, depth) when depth > 0 do
103103 {[], rest}
104104 end
105105106106- defp dec_key(<<@binary, rest::binary>>, depth) do
107107- {decoded_binary, rest} = dec_binary(rest)
108108- {values, tail} = dec_key(rest, depth)
106106+ defp decode(<<@binary, rest::binary>>, depth) do
107107+ {decoded_binary, rest} = decode_binary(rest)
108108+ {values, tail} = decode(rest, depth)
109109 {[decoded_binary | values], tail}
110110 end
111111112112- defp dec_key(<<@nested_list, rest::binary>>, depth) do
113113- {nested_values, rest} = dec_key(rest, depth + 1)
114114- {values, tail} = dec_key(rest, depth)
112112+ defp decode(<<@nested_list, rest::binary>>, depth) do
113113+ {nested_values, rest} = decode(rest, depth + 1)
114114+ {values, tail} = decode(rest, depth)
115115 {[nested_values | values], tail}
116116 end
117117118118- defp dec_key(<<@int_0, rest::binary>>, depth) do
119119- {values, tail} = dec_key(rest, depth)
118118+ defp decode(<<@int_0, rest::binary>>, depth) do
119119+ {values, tail} = decode(rest, depth)
120120 {[0 | values], tail}
121121 end
122122123123- defp dec_key(<<@int_pos_1, rest::binary>>, depth), do: dec_pos_integer(1, rest, depth)
124124- defp dec_key(<<@int_pos_2, rest::binary>>, depth), do: dec_pos_integer(2, rest, depth)
125125- defp dec_key(<<@int_pos_3, rest::binary>>, depth), do: dec_pos_integer(3, rest, depth)
126126- defp dec_key(<<@int_pos_4, rest::binary>>, depth), do: dec_pos_integer(4, rest, depth)
127127- defp dec_key(<<@int_pos_5, rest::binary>>, depth), do: dec_pos_integer(5, rest, depth)
128128- defp dec_key(<<@int_pos_6, rest::binary>>, depth), do: dec_pos_integer(6, rest, depth)
129129- defp dec_key(<<@int_pos_7, rest::binary>>, depth), do: dec_pos_integer(7, rest, depth)
130130- defp dec_key(<<@int_pos_8, rest::binary>>, depth), do: dec_pos_integer(8, rest, depth)
123123+ defp decode(<<@int_pos_1, rest::binary>>, depth), do: dec_pos_int(1, rest, depth)
124124+ defp decode(<<@int_pos_2, rest::binary>>, depth), do: dec_pos_int(2, rest, depth)
125125+ defp decode(<<@int_pos_3, rest::binary>>, depth), do: dec_pos_int(3, rest, depth)
126126+ defp decode(<<@int_pos_4, rest::binary>>, depth), do: dec_pos_int(4, rest, depth)
127127+ defp decode(<<@int_pos_5, rest::binary>>, depth), do: dec_pos_int(5, rest, depth)
128128+ defp decode(<<@int_pos_6, rest::binary>>, depth), do: dec_pos_int(6, rest, depth)
129129+ defp decode(<<@int_pos_7, rest::binary>>, depth), do: dec_pos_int(7, rest, depth)
130130+ defp decode(<<@int_pos_8, rest::binary>>, depth), do: dec_pos_int(8, rest, depth)
131131132132- defp dec_binary(binary) do
133133- {parts, tail} = dec_binary(binary, 0)
132132+ defp decode_binary(binary) do
133133+ {parts, tail} = decode_binary(binary, 0)
134134 {IO.iodata_to_binary(parts), tail}
135135 end
136136137137- defp dec_binary(binary, offset) do
137137+ defp decode_binary(binary, offset) do
138138 case binary do
139139 <<head::binary-size(offset), @nil_value, @escape, bin_tail::binary>> ->
140140 # Un-escape null byte and keep going
141141- {parts, tail} = dec_binary(bin_tail, 0)
141141+ {parts, tail} = decode_binary(bin_tail, 0)
142142 {[head, "\x00" | parts], tail}
143143144144 <<head::binary-size(offset), @nil_value, tail::binary>> ->
···147147148148 <<_head::binary-size(offset), _other, _tail::binary>> ->
149149 # Found any other byte, keep scanning
150150- dec_binary(binary, offset + 1)
150150+ decode_binary(binary, offset + 1)
151151152152 <<_head::binary-size(offset)>> -> raise "Encoded binary was not terminated: #{inspect(binary)}"
153153 end
154154 end
155155156156- defp dec_pos_integer(bytes, rest, depth) do
156156+ defp dec_pos_int(bytes, rest, depth) do
157157 <<int::unsigned-big-integer-size(bytes)-unit(8), rest::binary>> = rest
158158159159- {values, tail} = dec_key(rest, depth)
159159+ {values, tail} = decode(rest, depth)
160160 {[int | values], tail}
161161 end
162162end
+9-9
test/encoding_test.exs
···11defmodule Hobbes.EncTest do
22 use ExUnit.Case, async: true
3344- alias Hobbes.Enc
44+ alias Hobbes.Encoding.Keyset
5566- @moduletag :enc
66+ @moduletag :encoding
7788 # TODO: fuzz
99 describe "tuples" do
···1818 ]
19192020 for k <- keys do
2121- result = Enc.encode_key(k) |> Enc.decode_key()
2121+ result = Keyset.pack(k) |> Keyset.unpack()
2222 assert result == k
2323 end
2424 end
···3232 ]
33333434 for k <- keys do
3535- result = Enc.encode_key(k) |> Enc.decode_key()
3535+ result = Keyset.pack(k) |> Keyset.unpack()
3636 assert result == k
3737 end
3838 end
···4545 ]
46464747 for k <- keys do
4848- result = Enc.encode_key(k) |> Enc.decode_key()
4848+ result = Keyset.pack(k) |> Keyset.unpack()
4949 assert result == k
5050 end
5151 end
5252 end
53535454- describe "encode_key/1" do
5454+ describe "pack/1" do
5555 test "encodes integers" do
5656- assert "\x14" = Enc.encode_key([0])
5656+ assert "\x14" = Keyset.pack([0])
57575858- assert "\x17" <> rest = Enc.encode_key([1_000_000])
5858+ assert "\x17" <> rest = Keyset.pack([1_000_000])
5959 assert :binary.decode_unsigned(rest) == 1_000_000
60606161- assert "\x1D" <> rest = Enc.encode_key([(2 ** 64) - 1])
6161+ assert "\x1D" <> rest = Keyset.pack([(2 ** 64) - 1])
6262 assert rest == String.duplicate("\xFF", 8)
6363 end
6464 end