diff --git a/README.md b/README.md index c693ea70..5a5d836c 100644 --- a/README.md +++ b/README.md @@ -73,7 +73,7 @@ end use Protobuf, syntax: :proto3 @type t :: %__MODULE__{ - name: String.t + name: String.t() } defstruct [:name] @@ -84,7 +84,7 @@ end use Protobuf, syntax: :proto3 @type t :: %__MODULE__{ - message: String.t + message: String.t() } defstruct [:message] diff --git a/lib/google/compiler/plugin.pb.ex b/lib/google/compiler/plugin.pb.ex index 1a410092..be3f4aa1 100644 --- a/lib/google/compiler/plugin.pb.ex +++ b/lib/google/compiler/plugin.pb.ex @@ -33,7 +33,7 @@ defmodule Google.Protobuf.Compiler.CodeGeneratorRequest do use Protobuf, syntax: :proto2 @type t :: %__MODULE__{ - file_to_generate: String.t(), + file_to_generate: [String.t()], parameter: String.t(), proto_file: [Google.Protobuf.FileDescriptorProto.t()], compiler_version: Google.Protobuf.Compiler.Version.t() | nil diff --git a/lib/google/descriptor.pb.ex b/lib/google/descriptor.pb.ex index 81f82da1..a9fa8e19 100644 --- a/lib/google/descriptor.pb.ex +++ b/lib/google/descriptor.pb.ex @@ -115,9 +115,9 @@ defmodule Google.Protobuf.FileDescriptorProto do @type t :: %__MODULE__{ name: String.t(), package: String.t(), - dependency: String.t(), - public_dependency: integer, - weak_dependency: integer, + dependency: [String.t()], + public_dependency: [integer], + weak_dependency: [integer], message_type: [Google.Protobuf.DescriptorProto.t()], enum_type: [Google.Protobuf.EnumDescriptorProto.t()], service: [Google.Protobuf.ServiceDescriptorProto.t()], @@ -208,7 +208,7 @@ defmodule Google.Protobuf.DescriptorProto do oneof_decl: [Google.Protobuf.OneofDescriptorProto.t()], options: Google.Protobuf.MessageOptions.t() | nil, reserved_range: [Google.Protobuf.DescriptorProto.ReservedRange.t()], - reserved_name: String.t() + reserved_name: [String.t()] } defstruct [ @@ -346,7 +346,7 @@ defmodule Google.Protobuf.EnumDescriptorProto do value: [Google.Protobuf.EnumValueDescriptorProto.t()], options: Google.Protobuf.EnumOptions.t() | nil, reserved_range: [Google.Protobuf.EnumDescriptorProto.EnumReservedRange.t()], - reserved_name: String.t() + reserved_name: [String.t()] } defstruct [:name, :value, :options, :reserved_range, :reserved_name] @@ -762,11 +762,11 @@ defmodule Google.Protobuf.SourceCodeInfo.Location do use Protobuf, syntax: :proto2 @type t :: %__MODULE__{ - path: integer, - span: integer, + path: [integer], + span: [integer], leading_comments: String.t(), trailing_comments: String.t(), - leading_detached_comments: String.t() + leading_detached_comments: [String.t()] } defstruct [:path, :span, :leading_comments, :trailing_comments, :leading_detached_comments] @@ -800,7 +800,7 @@ defmodule Google.Protobuf.GeneratedCodeInfo.Annotation do use Protobuf, syntax: :proto2 @type t :: %__MODULE__{ - path: integer, + path: [integer], source_file: String.t(), begin: integer, end: integer diff --git a/lib/protobuf/protoc/generator/message.ex b/lib/protobuf/protoc/generator/message.ex index 13b936fe..7207531c 100644 --- a/lib/protobuf/protoc/generator/message.ex +++ b/lib/protobuf/protoc/generator/message.ex @@ -159,29 +159,32 @@ defmodule Protobuf.Protoc.Generator.Message do String.pad_trailing("#{name}:", len + 1) end - defp fmt_type(%{opts: %{map: true}, map: {{k_type, k_name}, {v_type, v_name}}}) do - k_type = type_to_spec(k_type, k_name) - v_type = type_to_spec(v_type, v_name) - "%{#{k_type} => #{v_type}}" + defp fmt_type(%{opts: %{map: true}, map: {{k_type_enum, _k_type}, {v_type_enum, v_type}}}) do + # Keys are guaranteed to be scalars. Values can be anything except another map. Map fields + # cannot be `repeated`. + k_spec = TypeUtil.enum_to_spec(k_type_enum) + v_spec = type_to_spec(v_type_enum, v_type) + v_spec = optional_if_message(v_type_enum, v_spec) + + "%{#{k_spec} => #{v_spec}}" end - defp fmt_type(%{label: "repeated", type_enum: type_enum, type: type}) do - type_to_spec(type_enum, type, true) - end + defp fmt_type(%{label: label, type_enum: type_enum, type: type}) do + spec = type_to_spec(type_enum, type) - defp fmt_type(%{type_enum: type_enum, type: type}) do - "#{type_to_spec(type_enum, type)}" + if label == "repeated" do + "[#{spec}]" + else + optional_if_message(type_enum, spec) + end end - defp type_to_spec(enum, type, repeated \\ false) - - defp type_to_spec(:TYPE_MESSAGE, type, repeated), - do: TypeUtil.enum_to_spec(:TYPE_MESSAGE, type, repeated) - - defp type_to_spec(:TYPE_ENUM, type, repeated), - do: TypeUtil.enum_to_spec(:TYPE_ENUM, type, repeated) + defp type_to_spec(:TYPE_MESSAGE, type), do: "#{type}.t()" + defp type_to_spec(:TYPE_ENUM, type), do: "#{type}.t()" + defp type_to_spec(type_scalar, _type), do: TypeUtil.enum_to_spec(type_scalar) - defp type_to_spec(enum, _, _), do: TypeUtil.enum_to_spec(enum) + defp optional_if_message(:TYPE_MESSAGE, spec), do: "#{spec} | nil" + defp optional_if_message(_type_others, spec), do: spec def get_fields(ctx, desc) do oneofs = Enum.map(desc.oneof_decl, & &1.name) diff --git a/lib/protobuf/type_util.ex b/lib/protobuf/type_util.ex index 8057623b..e21ac2a6 100644 --- a/lib/protobuf/type_util.ex +++ b/lib/protobuf/type_util.ex @@ -27,7 +27,9 @@ defmodule Protobuf.TypeUtil do def enum_to_spec(:TYPE_FIXED64), do: "non_neg_integer" def enum_to_spec(:TYPE_FIXED32), do: "non_neg_integer" def enum_to_spec(:TYPE_BOOL), do: "boolean" - def enum_to_spec(:TYPE_STRING), do: "String.t" + def enum_to_spec(:TYPE_STRING), do: "String.t()" + def enum_to_spec(:TYPE_GROUP), do: "any" + def enum_to_spec(:TYPE_MESSAGE), do: "binary" def enum_to_spec(:TYPE_BYTES), do: "binary" def enum_to_spec(:TYPE_UINT32), do: "non_neg_integer" def enum_to_spec(:TYPE_ENUM), do: "integer" @@ -35,9 +37,4 @@ defmodule Protobuf.TypeUtil do def enum_to_spec(:TYPE_SFIXED64), do: "integer" def enum_to_spec(:TYPE_SINT32), do: "integer" def enum_to_spec(:TYPE_SINT64), do: "integer" - def enum_to_spec(_), do: "any" - def enum_to_spec(:TYPE_MESSAGE, type, true = _repeated), do: "[#{type}.t]" - def enum_to_spec(:TYPE_MESSAGE, type, false = _repeated), do: "#{type}.t | nil" - def enum_to_spec(:TYPE_ENUM, type, true = _repeated), do: "[#{type}.t]" - def enum_to_spec(:TYPE_ENUM, type, false = _repeated), do: "#{type}.t" end diff --git a/test/protobuf/protoc/generator/message_test.exs b/test/protobuf/protoc/generator/message_test.exs index 7f154045..d7b673db 100644 --- a/test/protobuf/protoc/generator/message_test.exs +++ b/test/protobuf/protoc/generator/message_test.exs @@ -81,7 +81,7 @@ defmodule Protobuf.Protoc.Generator.MessageTest do {[], [msg]} = Generator.generate(ctx, desc) assert msg =~ "defstruct [:a, :b]\n" assert msg =~ "a: integer" - assert msg =~ "b: String.t" + assert msg =~ "b: String.t()" assert msg =~ "field :a, 1, optional: true, type: :int32\n" assert msg =~ "field :b, 2, required: true, type: :string\n" end @@ -120,7 +120,7 @@ defmodule Protobuf.Protoc.Generator.MessageTest do {[], [msg]} = Generator.generate(ctx, desc) assert msg =~ "defstruct [:a, :b, :c]\n" assert msg =~ "a: integer" - assert msg =~ "b: String.t" + assert msg =~ "b: String.t()" assert msg =~ "field :a, 1, type: :int32\n" assert msg =~ "field :b, 2, type: :string\n" assert msg =~ "field :c, 3, repeated: true, type: :int32\n" @@ -226,8 +226,8 @@ defmodule Protobuf.Protoc.Generator.MessageTest do ) {[], [msg]} = Generator.generate(ctx, desc) - assert msg =~ "bar: Bar.t | nil" - assert msg =~ "baz: [Baz.t]" + assert msg =~ "bar: Bar.t() | nil" + assert msg =~ "baz: [Baz.t()]" end test "generate/2 supports map field" do @@ -279,7 +279,7 @@ defmodule Protobuf.Protoc.Generator.MessageTest do ) {[[]], [_, msg]} = Generator.generate(ctx, desc) - assert msg =~ "a: %{integer => FooBar.AbCd.Bar.t | nil}" + assert msg =~ "a: %{integer => FooBar.AbCd.Bar.t() | nil}" assert msg =~ "field :a, 1, repeated: true, type: FooBar.AbCd.Foo.ProjectsEntry, map: true\n" end @@ -307,7 +307,7 @@ defmodule Protobuf.Protoc.Generator.MessageTest do ) {[], [msg]} = Generator.generate(ctx, desc) - assert msg =~ "a: FooBar.AbCd.EnumFoo.t" + assert msg =~ "a: FooBar.AbCd.EnumFoo.t()" assert msg =~ "field :a, 1, optional: true, type: FooBar.AbCd.EnumFoo, enum: true\n" end @@ -358,7 +358,7 @@ defmodule Protobuf.Protoc.Generator.MessageTest do ) {[], [msg]} = Generator.generate(ctx, desc) - assert msg =~ "a: OtherPkg.MsgFoo.t" + assert msg =~ "a: OtherPkg.MsgFoo.t()" assert msg =~ "field :a, 1, optional: true, type: OtherPkg.MsgFoo\n" end @@ -552,6 +552,6 @@ defmodule Protobuf.Protoc.Generator.MessageTest do ) {[], [msg]} = Generator.generate(ctx, desc) - assert msg =~ "a: [FooBar.AbCd.EnumFoo.t]" + assert msg =~ "a: [FooBar.AbCd.EnumFoo.t()]" end end diff --git a/test/protobuf/protoc/proto_gen/test.pb.ex b/test/protobuf/protoc/proto_gen/test.pb.ex index 9be7590e..965f49f2 100644 --- a/test/protobuf/protoc/proto_gen/test.pb.ex +++ b/test/protobuf/protoc/proto_gen/test.pb.ex @@ -90,7 +90,7 @@ defmodule My.Test.Request do use Protobuf, syntax: :proto2 @type t :: %__MODULE__{ - key: integer, + key: [integer], hue: My.Test.Request.Color.t(), hat: My.Test.HatType.t(), deadline: float | :infinity | :negative_infinity | :nan, @@ -151,7 +151,7 @@ defmodule My.Test.Reply do @type t :: %__MODULE__{ found: [My.Test.Reply.Entry.t()], - compact_keys: integer, + compact_keys: [integer], __pb_extensions__: map }