Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
35 changes: 21 additions & 14 deletions lib/protobuf/decoder.ex
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,7 @@ defmodule Protobuf.Decoder do

bin
|> build_message(struct(module), props)
|> reverse_repeated(repeated_fields)
|> Map.update!(:__unknown_fields__, &Enum.reverse/1)
|> reverse_repeated([:__unknown_fields__ | repeated_fields])
|> transform_module(module)
end

Expand Down Expand Up @@ -173,12 +172,12 @@ defmodule Protobuf.Decoder do
defp handle_value(<<rest::bits>>, field_number, wire_type, value, message, props) do
case props.field_props do
%{^field_number => %FieldProps{packed?: true, name_atom: name_atom} = prop} ->
new_message = update_in_message(message, name_atom, &value_for_packed(value, &1, prop))
new_message = update_in_message(message, name_atom, value, &value_for_packed/3, prop)
build_message(rest, new_message, props)

%{^field_number => %FieldProps{wire_type: ^wire_type} = prop} ->
key = field_key(prop, props)
new_message = update_in_message(message, key, &value_for_field(value, &1, prop))
new_message = update_in_message(message, key, value, &value_for_field/3, prop)
build_message(rest, new_message, props)

# Repeated fields of primitive numeric types can be "packed". Their packed? flag will be
Expand All @@ -187,7 +186,7 @@ defmodule Protobuf.Decoder do
# https://developers.google.com/protocol-buffers/docs/encoding#packed
%{^field_number => %FieldProps{repeated?: true, name_atom: name_atom} = prop}
when wire_type == wire_delimited() ->
new_message = update_in_message(message, name_atom, &value_for_packed(value, &1, prop))
new_message = update_in_message(message, name_atom, value, &value_for_packed/3, prop)
build_message(rest, new_message, props)

%{^field_number => %FieldProps{wire_type: expected, name: field}} ->
Expand Down Expand Up @@ -374,16 +373,21 @@ defmodule Protobuf.Decoder do

defp decode_fixed64(<<>>, _type, acc), do: acc

defp reverse_repeated(message, repeated_fields) do
Enum.reduce(repeated_fields, message, fn repeated_field, message_acc ->
case message_acc do
%{^repeated_field => values} when is_list(values) ->
%{message_acc | repeated_field => Enum.reverse(values)}
defp reverse_repeated(message, [repeated_field | rest]) do
message =
case message do
%{^repeated_field => [_, _ | _] = values} ->
%{message | repeated_field => Enum.reverse(values)}

_other ->
message_acc
message
end
end)

reverse_repeated(message, rest)
end

defp reverse_repeated(message, []) do
message
end

defp field_key(%FieldProps{oneof: nil, name_atom: key}, _message_props) do
Expand All @@ -395,13 +399,16 @@ defmodule Protobuf.Decoder do
key
end

defp update_in_message(message, key, update_fun) do
# Receives an update_fun and calls it with value and props params to avoid
# the extra memory usage of creating an anonymous function with the two
# two params in it's context
defp update_in_message(message, key, value, update_fun, props) do
current =
case message do
%_{^key => value} -> value
%_{} -> nil
end

Map.put(message, key, update_fun.(current))
Map.put(message, key, update_fun.(value, current, props))
end
end