Packages
protox
1.6.8
2.0.9
2.0.8
2.0.7
2.0.6
2.0.5
2.0.4
2.0.3
2.0.2
2.0.1
2.0.0
2.0.0-dev
1.7.8
1.7.7
1.7.6
1.7.5
1.7.4
retired
1.7.3
1.7.2
1.7.1
1.7.0
1.6.10
1.6.9
1.6.8
1.6.7
1.6.6
1.6.5
1.6.4
1.6.3
1.6.2
1.6.1
1.6.0
1.5.1
1.5.0
1.4.0
1.3.2
1.3.1
1.3.0
1.2.4
1.2.3
1.2.2
1.2.1
1.2.0
1.1.1
1.1.0
1.0.0
0.25.0
0.24.0
0.23.1
0.23.0
0.22.0
0.21.0
0.20.0
0.19.1
0.19.0
0.18.0
0.17.0
0.16.2
0.16.1
0.16.0
0.15.2
0.15.1
0.15.0
0.14.0
0.13.0
0.12.1
0.12.0
0.11.1
0.11.0
0.10.0
0.9.1
0.9.0
0.8.0
0.7.1
0.7.0
A fast, easy to use and 100% conformant Elixir library for Google Protocol Buffers (aka protobuf)
Current section
Files
Jump to
Current section
Files
lib/protox/json_encode.ex
defmodule Protox.JsonEncode do
@moduledoc false
alias Protox.Field
use Protox.Float
@spec encode!(struct(), fun()) :: iodata()
def encode!(msg, json_encode) do
Protox.JsonMessageEncoder.encode_message(msg, json_encode)
end
def encode_message(msg, json_encode) do
initial_acc = ["}"]
body =
msg.__struct__.fields_defs()
|> Enum.reduce(initial_acc, fn %Protox.Field{} = field, acc ->
case encode_msg_field(msg, field, json_encode) do
<<>> ->
acc
encoded ->
case acc do
^initial_acc -> [encoded | acc]
_ -> [encoded, "," | acc]
end
end
end)
["{" | body]
end
def encode_enum(enum, value, json_encode) when is_atom(value) do
if enum.__struct__.has_constant?(value) do
json_encode.(value)
else
raise Protox.JsonEncodingError.new("invalid enum entry value")
end
end
def encode_enum(enum, value, json_encode) do
value |> enum.__struct__.decode() |> json_encode.()
end
def encode_value(value, :bytes, _json_encode), do: "\"#{Base.url_encode64(value)}\""
def encode_value(:infinity, _type, _json_encode), do: "\"Infinity\""
def encode_value(:"-infinity", _type, _json_encode), do: "\"-Infinity\""
def encode_value(:nan, _type, _json_encode), do: "\"NaN\""
def encode_value(value, :int64, _json_encode), do: "\"#{value}\""
def encode_value(value, :uint64, _json_encode), do: "\"#{value}\""
def encode_value(value, :fixed64, _json_encode), do: "\"#{value}\""
def encode_value(value, :sfixed64, _json_encode), do: "\"#{value}\""
def encode_value(true, :bool, _json_encode), do: "true"
def encode_value(value, {:enum, enum}, json_encode) do
Protox.JsonEnumEncoder.encode_enum(struct(enum), value, json_encode)
end
def encode_value(value, {:message, _}, json_encode) do
Protox.JsonMessageEncoder.encode_message(value, json_encode)
end
def encode_value(value, _type, json_encode), do: json_encode.(value)
# -- Private
defp encode_msg_field(
msg,
%Field{name: child_name, kind: {:oneof, parent_name}} = field,
json_encode
) do
case Map.fetch!(msg, parent_name) do
{^child_name, field_value} ->
json_value = encode_value(field_value, field.type, json_encode)
[json_encode.(field.json_name), ":", json_value]
_ ->
<<>>
end
end
defp encode_msg_field(msg, %Field{} = field, json_encode) do
field_value = Map.fetch!(msg, field.name)
json_value = encode_field(field, field_value, json_encode, msg.__struct__.syntax())
case json_value do
<<>> -> <<>>
_ -> [json_encode.(field.json_name), ":", json_value]
end
end
defp encode_field(%Field{label: :repeated}, [], _json_encode, _syntax), do: <<>>
defp encode_field(%Field{label: :repeated, type: type}, value, json_encode, _syntax) do
initial_acc = ["]"]
res =
value
|> Enum.reverse()
|> Enum.reduce(initial_acc, fn v, acc ->
v_json = encode_value(v, type, json_encode)
case acc do
^initial_acc -> [v_json | acc]
_ -> [v_json, "," | acc]
end
end)
["[" | res]
end
defp encode_field(%Field{}, nil, _json_encode, _syntax) do
<<>>
end
defp encode_field(%Field{kind: {:scalar, default_value}}, value, _json_encode, :proto3)
when value == default_value do
<<>>
end
defp encode_field(
%Field{kind: {:scalar, _default_value}, type: type},
value,
json_encode,
_syntax
) do
encode_value(value, type, json_encode)
end
defp encode_field(%Field{kind: :map}, value, _json_encode, _syntax) when map_size(value) == 0,
do: <<>>
defp encode_field(
%Field{kind: :map, type: {_key_type, value_type}},
value,
json_encode,
_syntax
) do
initial_acc = ["}"]
res =
Enum.reduce(value, initial_acc, fn {k, v}, acc ->
k_json = k |> to_string() |> json_encode.()
v_json = encode_value(v, value_type, json_encode)
case acc do
^initial_acc -> [k_json, ":", v_json | acc]
_ -> [k_json, ":", v_json, "," | acc]
end
end)
["{" | res]
end
end