Skip to content

Commit

Permalink
Merge pull request #2 from OffgridElectric/struct_defaults
Browse files Browse the repository at this point in the history
Set sensible defaults for structs
  • Loading branch information
zolakeith authored Jul 29, 2021
2 parents dab77e9 + 6c7878b commit 8c47468
Show file tree
Hide file tree
Showing 3 changed files with 35 additions and 28 deletions.
29 changes: 19 additions & 10 deletions lib/protobuf/protoc/generator/message.ex
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ defmodule Protobuf.Protoc.Generator.Message do
new_namespace: new_ns,
name: Util.mod_name(ctx, new_ns),
options: msg_opts_str(ctx, desc.options),
structs: structs_str(desc, extensions),
structs: structs_str(ctx, desc, extensions),
typespec: typespec_str(fields, desc.oneof_decl, extensions),
fields: fields,
oneofs: oneofs_str(desc.oneof_decl),
Expand Down Expand Up @@ -89,19 +89,28 @@ defmodule Protobuf.Protoc.Generator.Message do
if String.length(str) > 0, do: ", " <> str, else: ""
end

def structs_str(struct, extensions) do
fields = Enum.filter(struct.field, fn f -> !f.oneof_index end)
def structs_str(ctx, desc, extensions) do
oneof_fields = Enum.map(desc.oneof_decl, &{&1.name, nil})
proto3? = ctx.syntax == :proto3

fields =
if Enum.empty?(extensions) do
fields
else
fields ++ [%{name: :__pb_extensions__}]
end
fields = for f <- desc.field, !f.oneof_index, do: {f.name, struct_default_value(f, proto3?)}

extensions = if Enum.empty?(extensions), do: [], else: [{:__pb_extensions__, nil}]

Enum.map_join(struct.oneof_decl ++ fields, ", ", fn f -> ":#{f.name}" end)
Enum.map_join(oneof_fields ++ fields ++ extensions, ", ", fn {name, default_value} ->
"#{name}: #{default_value || inspect(nil)}"
end)
end

defp struct_default_value(%{default_value: nil, label: :LABEL_REPEATED} = _field, _proto3?),
do: "[]"

defp struct_default_value(%{type: type, default_value: nil} = _field, true = _proto3?),
do: type |> TypeUtil.from_enum() |> Protobuf.Builder.type_default() |> inspect()

defp struct_default_value(%{type: type, default_value: default_value} = _field, _proto3?),
do: default_value(type, default_value)

def typespec_str([], [], []), do: " @type t :: %__MODULE__{}\n"
def typespec_str([], [], [_ | _]), do: " @type t :: %__MODULE__{__pb_extensions__: map}\n"

Expand Down
10 changes: 5 additions & 5 deletions test/protobuf/protoc/generator/message_test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ defmodule Protobuf.Protoc.Generator.MessageTest do
)

{[], [msg]} = Generator.generate(ctx, desc)
assert msg =~ "defstruct [:a, :b]\n"
assert msg =~ "defstruct [a: nil, b: nil]\n"
assert msg =~ "a: integer"
assert msg =~ "b: String.t"
assert msg =~ "field :a, 1, optional: true, type: :int32\n"
Expand Down Expand Up @@ -106,7 +106,7 @@ defmodule Protobuf.Protoc.Generator.MessageTest do
)

{[], [msg]} = Generator.generate(ctx, desc)
assert msg =~ "defstruct [:a, :b, :c]\n"
assert msg =~ "defstruct [a: 0, b: \"\", c: []]\n"
assert msg =~ "a: integer"
assert msg =~ "b: String.t"
assert msg =~ "field :a, 1, type: :int32\n"
Expand Down Expand Up @@ -452,7 +452,7 @@ defmodule Protobuf.Protoc.Generator.MessageTest do
assert msg =~ "second: {atom, any},\n"
assert msg =~ "other: integer\n"
refute msg =~ "a: integer,\n"
assert msg =~ "defstruct [:first, :second, :other]\n"
assert msg =~ "defstruct [first: nil, second: nil, other: nil]\n"
assert msg =~ "oneof :first, 0\n"
assert msg =~ "oneof :second, 1\n"
assert msg =~ "field :a, 1, optional: true, type: :int32, oneof: 0\n"
Expand Down Expand Up @@ -488,7 +488,7 @@ defmodule Protobuf.Protoc.Generator.MessageTest do
)

{[], [msg]} = Generator.generate(ctx, desc)
assert msg =~ "defstruct [:simple, :the_field_name]\n"
assert msg =~ "defstruct [simple: 0, the_field_name: \"\"]\n"
assert msg =~ "field :simple, 1, type: :int32\n"
assert msg =~ "field :the_field_name, 2, type: :string, json_name: \"theFieldName\"\n"
end
Expand All @@ -511,7 +511,7 @@ defmodule Protobuf.Protoc.Generator.MessageTest do
)

{[], [msg]} = Generator.generate(ctx, desc)
assert msg =~ "defstruct [:the_field_name]\n"
assert msg =~ "defstruct [the_field_name: nil]\n"
assert msg =~ "field :the_field_name, 1, required: true, type: :string\n"
end
end
Expand Down
24 changes: 11 additions & 13 deletions test/protobuf/protoc/proto_gen/test.pb.ex
Original file line number Diff line number Diff line change
Expand Up @@ -95,17 +95,15 @@ defmodule My.Test.Request do
reset: integer,
get_key: String.t()
}
defstruct [
:key,
:hue,
:hat,
:deadline,
:somegroup,
:name_mapping,
:msg_mapping,
:reset,
:get_key
]
defstruct key: [],
hue: nil,
hat: :FEDORA,
deadline: "inf",
somegroup: nil,
name_mapping: [],
msg_mapping: [],
reset: nil,
get_key: nil

field :key, 1, repeated: true, type: :int64
field :hue, 3, optional: true, type: My.Test.Request.Color, enum: true
Expand All @@ -127,7 +125,7 @@ defmodule My.Test.Reply.Entry do
value: integer,
_my_field_name_2: integer
}
defstruct [:key_that_needs_1234camel_CasIng, :value, :_my_field_name_2]
defstruct key_that_needs_1234camel_CasIng: nil, value: 7, _my_field_name_2: nil

field :key_that_needs_1234camel_CasIng, 1, required: true, type: :int64
field :value, 2, optional: true, type: :int64, default: 7
Expand All @@ -143,7 +141,7 @@ defmodule My.Test.Reply do
compact_keys: [integer],
__pb_extensions__: map
}
defstruct [:found, :compact_keys, :__pb_extensions__]
defstruct found: [], compact_keys: [], __pb_extensions__: nil

field :found, 1, repeated: true, type: My.Test.Reply.Entry
field :compact_keys, 2, repeated: true, type: :int32, packed: true
Expand Down

0 comments on commit 8c47468

Please sign in to comment.