Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
WIP (Merge binaries, exts, collections handling into main function)
  • Loading branch information
lexmag committed Apr 11, 2017
1 parent 5e3a213 commit 08549bf
Showing 1 changed file with 37 additions and 57 deletions.
94 changes: 37 additions & 57 deletions lib/msgpax/unpacker.ex
Expand Up @@ -25,7 +25,7 @@ defmodule Msgpax.Unpacker do
@moduledoc false

def unpack(<<buffer::bits>>, options) do
unpack(buffer, [], options)
unpack(buffer, [], options, [:root], 0, 1)
end

formats = %{
Expand Down Expand Up @@ -61,14 +61,14 @@ defmodule Msgpax.Unpacker do
quote(do: [0xD3, val::64-signed-integer]) => {:value, quote(do: val)},

# Array
quote(do: [0b1001::4, len::4]) => {:call, quote(do: unpack_list(len))},
quote(do: [0xDC, len::16]) => {:call, quote(do: unpack_list(len))},
quote(do: [0xDD, len::32]) => {:call, quote(do: unpack_list(len))},
quote(do: [0b1001::4, len::4]) => {:collection, :list},
quote(do: [0xDC, len::16]) => {:collection, :list},
quote(do: [0xDD, len::32]) => {:collection, :list},

# Map
quote(do: [0b1000::4, len::4]) => {:call, quote(do: unpack_map(len))},
quote(do: [0xDE, len::16]) => {:call, quote(do: unpack_map(len))},
quote(do: [0xDF, len::32]) => {:call, quote(do: unpack_map(len))},
quote(do: [0b1000::4, len::4]) => {:collection, :map},
quote(do: [0xDE, len::16]) => {:collection, :map},
quote(do: [0xDF, len::32]) => {:collection, :map},

# Extension
quote(do: [0xD4, type, val::1-bytes]) => {:call, quote(do: unpack_ext(type, val))},
Expand All @@ -84,77 +84,65 @@ defmodule Msgpax.Unpacker do
import Macro, only: [pipe: 3]

for {format, {:value, value}} <- formats do
defp unpack(<<unquote_splicing(format), rest::bits>>, [], options) do
unpack(rest, [unquote(value)], options)
defp unpack(<<unquote_splicing(format), rest::bits>>, result, options, outer, index, count) when index < count do
unpack(rest, [unquote(value) | result], options, outer, index + 1, count)
end
end

for {format, {:call, call}} <- formats do
rest = Macro.var(:rest, nil)
options = Macro.var(:options, nil)
defp unpack(<<unquote_splicing(format), rest::bits>>, [], options) do
unquote(pipe(rest, pipe([], pipe(options, pipe([], call, 0), 0), 0), 0))
defp unpack(<<unquote_splicing(format), rest::bits>>, result, options, outer, index, count) when index < count do
unpack(rest, [unquote(pipe(options, call, 0)) | result], options, outer, index + 1, count)
end
end

defp unpack(<<byte, _::bits>>, [], _options) do
throw {:bad_format, byte}
end

defp unpack(<<_::bits>>, [], _options) do
throw :incomplete
end

defp unpack(buffer, [value], _options) do
{value, buffer}
for {format, {:collection, :list = kind}} <- formats do
defp unpack(<<unquote_splicing(format), rest::bits>>, result, options, [kind | outer], index, count) when index < count do
unpack(rest, result, options, [unquote(kind), {kind, index, count} | outer], 0, unquote(quote(do: len)))
end
end

defp unpack_binary(<<buffer::bits>>, result, %{binary: true} = options, outer, value) do
unpack_continue(buffer, [Msgpax.Bin.new(value) | result], options, outer)
for {format, {:collection, :map = kind}} <- formats do
defp unpack(<<unquote_splicing(format), rest::bits>>, result, options, [kind | outer], index, count) when index < count do
unpack(rest, result, options, [unquote(kind), {kind, index, count} | outer], 0, unquote(quote(do: len)) * 2)
end
end

defp unpack_binary(<<buffer::bits>>, result, options, outer, value) do
unpack_continue(buffer, [value | result], options, outer)
defp unpack(<<buffer::bits>>, result, options, [kind, {next, index, size} | outer], count, count) do
unpack(buffer, build_collection(result, count, kind), options, [next | outer], index + 1, size)
end

defp unpack_list(<<buffer::bits>>, result, options, outer, length) do
unpack_collection(buffer, result, options, outer, 0, length, :list)
defp unpack(<<byte, _::bits>>, [], _options, _outer, _index, _count) do
throw {:bad_format, byte}
end

for {format, {:value, value}} <- formats do
defp unpack_collection(<<unquote_splicing(format), rest::bits>>, result, options, outer, index, length, kind) when index < length do
unpack_collection(rest, [unquote(value) | result], options, outer, index + 1, length, kind)
end
defp unpack(<<_::bits>>, [], _options, _outer, _index, _count) do
throw :incomplete
end

for {format, {:call, call}} <- formats do
rest = Macro.var(:rest, nil)
result = Macro.var(:result, nil)
options = Macro.var(:options, nil)
outer = Macro.var(:outer, nil)
defp unpack_collection(<<unquote_splicing(format), rest::bits>>, result, options, outer, index, length, kind) when index < length do
outer = [{kind, index, length} | outer]
unquote(pipe(rest, pipe(result, pipe(options, pipe(outer, call, 0), 0), 0), 0))
end
defp unpack(buffer, [value], _options, [:root], count, count) do
{value, buffer}
end

defp unpack_collection(<<buffer::bits>>, result, options, outer, count, count, kind) do
unpack_continue(buffer, build_collection(result, count, kind), options, outer)
defp unpack_binary(%{binary: true}, value) do
Msgpax.Bin.new(value)
end

defp unpack_map(<<buffer::bits>>, result, options, outer, length) do
unpack_collection(buffer, result, options, outer, 0, length * 2, :map)
defp unpack_binary(_options, value) do
value
end

defp unpack_ext(<<buffer::bits>>, result, options, outer, type, data) do
defp unpack_ext(options, type, data) do
if type in 0..127 do
unpack_continue(buffer, [unpack_ext(type, data, options) | result], options, outer)
unpack_ext_module(type, data, options)
else
throw {:not_supported_ext, type}
end
end

defp unpack_ext(type, data, %{ext: module}) when is_atom(module) do
@compile {:inline, [unpack_ext_module: 3]}

defp unpack_ext_module(type, data, %{ext: module}) when is_atom(module) do
case module.unpack(Msgpax.Ext.new(type, data)) do
{:ok, result} ->
result
Expand All @@ -163,18 +151,10 @@ defmodule Msgpax.Unpacker do
end
end

defp unpack_ext(type, data, _options) do
defp unpack_ext_module(type, data, _options) do
Msgpax.Ext.new(type, data)
end

defp unpack_continue(<<buffer::bits>>, result, options, [{kind, index, length} | outer]) do
unpack_collection(buffer, result, options, outer, index + 1, length, kind)
end

defp unpack_continue(<<buffer::bits>>, result, options, []) do
unpack(buffer, result, options)
end

@compile {:inline, [build_collection: 3]}

defp build_collection(result, count, :list) do
Expand Down

0 comments on commit 08549bf

Please sign in to comment.