Skip to content

Commit 0cb92be

Browse files
authored
Deprecate the new(!)/0,1 callbacks (#330)
1 parent cf9f2a6 commit 0cb92be

33 files changed

+1042
-1080
lines changed

README.md

Lines changed: 4 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,7 @@ end
7979
8080
field :name, 1, type: :string
8181
end
82-
82+
8383
defmodule Helloworld.HelloReply do
8484
@moduledoc false
8585
use Protobuf, protoc_gen_elixir_version: "0.10.0", syntax: :proto3
@@ -91,17 +91,13 @@ end
9191
### Encode and decode in your code
9292

9393
```elixir
94-
struct = Foo.new(a: 3.2, c: Foo.Bar.new())
94+
struct = %Foo{a: 3.2, c: %Foo.Bar{}}
9595
encoded = Foo.encode(struct)
9696
struct = Foo.decode(encoded)
9797
```
9898

99-
Note:
100-
101-
- Use `YourModule.new(field: "value")` to ensure default values are set correctly for all fields
102-
instead of using the struct directly, as in `%YourModule{field: "value"}`.
103-
- Validation is done during encoding. An error will be raised if the struct is invalid: when it
104-
misses a required field or has a mistyped value.
99+
Validation is done during encoding. An error will be raised if the struct is invalid: when it
100+
misses a required field or has a mistyped value.
105101

106102
### Descriptor support
107103

conformance/protobuf/runner.ex

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -47,8 +47,10 @@ defmodule Conformance.Protobuf.Runner do
4747
raise "failed to read #{len} bytes from stdio: #{inspect(reason)}"
4848

4949
encoded_request when byte_size(encoded_request) == len ->
50-
mod = Conformance.ConformanceResponse
51-
response = mod.new!(result: handle_encoded_request(encoded_request))
50+
response =
51+
struct!(Conformance.ConformanceResponse,
52+
result: handle_encoded_request(encoded_request)
53+
)
5254

5355
encoded_response = Protobuf.encode(response)
5456

lib/protobuf.ex

Lines changed: 26 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -42,16 +42,19 @@ defmodule Protobuf do
4242

4343
@behaviour Protobuf
4444

45+
@deprecated "Build the struct by hand with %MyMessage{...} or use struct/1"
4546
@impl unquote(__MODULE__)
4647
def new() do
4748
Protobuf.Builder.new(__MODULE__)
4849
end
4950

51+
@deprecated "Build the struct by hand with %MyMessage{...} or use struct/2"
5052
@impl unquote(__MODULE__)
5153
def new(attrs) do
5254
Protobuf.Builder.new(__MODULE__, attrs)
5355
end
5456

57+
@deprecated "Build the struct by hand with %MyMessage{...} or use struct!/2"
5558
@impl unquote(__MODULE__)
5659
def new!(attrs) do
5760
Protobuf.Builder.new!(__MODULE__, attrs)
@@ -73,10 +76,13 @@ defmodule Protobuf do
7376
end
7477

7578
@doc """
76-
Builds a blank struct with default values. This and other "new" functions are
77-
preferred than raw building struct method like `%Foo{}`.
79+
Builds a blank struct with default values.
80+
81+
> #### Deprecated {: .warning}
82+
>
83+
> This is deprecated in favor of building the struct with `%MyMessage{...}` or using
84+
> `struct/1`.
7885
79-
In proto3, the zero values are the default values.
8086
"""
8187
@callback new() :: struct()
8288

@@ -85,10 +91,14 @@ defmodule Protobuf do
8591
8692
This function will:
8793
88-
* Recursively call `c:new/1` for embedded fields
89-
* Create structs using `struct/2` for keyword lists and maps
90-
* Create the correct struct if passed the wrong struct
91-
* Call `c:new/1` for each element in the list for repeated fields
94+
* Recursively call `c:new/1` for embedded fields
95+
* Create structs using `struct/2` for keyword lists and maps
96+
* Create the correct struct if passed the wrong struct
97+
* Call `c:new/1` for each element in the list for repeated fields
98+
99+
> #### Deprecated {: .warning}
100+
> This is deprecated in favor of building the struct with `%MyMessage{...}` or using
101+
> `struct/2`.
92102
93103
## Examples
94104
@@ -105,13 +115,18 @@ defmodule Protobuf do
105115
#=> %MyMessage{repeated: [%MyRepeated{field1: "foo"}, %MyRepeated{field1: "bar"}]}
106116
107117
"""
108-
@callback new(Enum.t()) :: struct
118+
@callback new(attributes :: Enum.t()) :: struct
109119

110120
@doc """
111121
Similar to `c:new/1`, but use `struct!/2` to build the struct, so
112122
errors will be raised if unknown keys are passed.
123+
124+
> #### Deprecated {: .warning}
125+
> This is deprecated in favor of building the struct with `%MyMessage{...}` or using
126+
> `struct!/2` directly.
127+
113128
"""
114-
@callback new!(Enum.t()) :: struct()
129+
@callback new!(attributes :: Enum.t()) :: struct()
115130

116131
@doc """
117132
Encodes the given struct into to a Protobuf binary.
@@ -167,8 +182,7 @@ defmodule Protobuf do
167182
168183
## Examples
169184
170-
struct = MyMessage.new()
171-
Protobuf.encode(struct)
185+
Protobuf.encode(%MyMessage{...})
172186
#=> <<...>>
173187
174188
"""
@@ -180,8 +194,7 @@ defmodule Protobuf do
180194
181195
## Examples
182196
183-
struct = MyMessage.new()
184-
Protobuf.encode_to_iodata(struct)
197+
Protobuf.encode_to_iodata(%MyMessage{...})
185198
#=> [...]
186199
187200
"""

lib/protobuf/any.ex

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -12,14 +12,15 @@ defmodule Protobuf.Any do
1212
1313
You can build and decode the `Any` type yourself.
1414
15-
encoded_any = Google.Protobuf.Any.new!(
16-
type_url: "type.googleapis.com/google.protobuf.Duration",
17-
value: Google.Protobuf.Duration.encode(%Google.Protobuf.Duration{seconds: 1})
18-
)
19-
20-
# Back to the original message:
21-
decoded_any = decoded Google.Protobuf.Any.decode(encoded_any)
22-
Google.Protobuf.Duration.decode(decoded_any.value)
15+
iex> value = %Google.Protobuf.Duration{seconds: 1}
16+
iex> any = %Google.Protobuf.Any{
17+
...> type_url: "type.googleapis.com/google.protobuf.Duration",
18+
...> value: Google.Protobuf.Duration.encode(value)
19+
...> }
20+
iex> encoded_any = Google.Protobuf.Any.encode(any)
21+
iex> decoded_any = Google.Protobuf.Any.decode(encoded_any)
22+
iex> Google.Protobuf.Duration.decode(decoded_any.value) == value
23+
true
2324
2425
"""
2526

lib/protobuf/decoder.ex

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ defmodule Protobuf.Decoder do
1414
%MessageProps{repeated_fields: repeated_fields} = props = module.__message_props__()
1515

1616
bin
17-
|> build_message(module.new(), props)
17+
|> build_message(struct(module), props)
1818
|> reverse_repeated(repeated_fields)
1919
|> Map.update!(:__unknown_fields__, &Enum.reverse/1)
2020
|> transform_module(module)

lib/protobuf/encoder.ex

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -144,7 +144,8 @@ defmodule Protobuf.Encoder do
144144
defp encode_from_type(mod, msg) do
145145
case msg do
146146
%{__struct__: ^mod} -> encode_to_iodata(msg)
147-
_ -> encode_to_iodata(mod.new(msg))
147+
%_{} -> encode_to_iodata(struct(mod, Map.from_struct(msg)))
148+
_ -> encode_to_iodata(struct(mod, msg))
148149
end
149150
end
150151

lib/protobuf/extension.ex

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,9 +29,10 @@ defmodule Protobuf.Extension do
2929
extend Foo, :my_custom, 1047, optional: true, type: :string
3030
end
3131
32-
foo = Foo.new()
32+
foo = %Foo{}
3333
Foo.put_extension(foo, Ext.PbExtension, :my_custom, "Custom field")
3434
Foo.get_extension(foo, Ext.PbExtension, :my_custom)
35+
3536
"""
3637

3738
@doc "The actual function for `put_extension`"

lib/protobuf/json.ex

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ defmodule Protobuf.JSON do
4949
5050
With `encode/1` you can turn any `Protobuf` message struct into a JSON string:
5151
52-
iex> message = Car.new(color: :RED, top_speed: 125.3)
52+
iex> message = %Car{color: :RED, top_speed: 125.3}
5353
iex> Protobuf.JSON.encode(message)
5454
{:ok, "{\\"color\\":\\"RED\\",\\"topSpeed\\":125.3}"}
5555
@@ -101,7 +101,7 @@ defmodule Protobuf.JSON do
101101
102102
## Examples
103103
104-
iex> Car.new(top_speed: 80.0) |> Protobuf.JSON.encode!()
104+
iex> Protobuf.JSON.encode!(%Car{top_speed: 80.0})
105105
~S|{"topSpeed":80.0}|
106106
107107
"""
@@ -143,13 +143,13 @@ defmodule Protobuf.JSON do
143143
144144
Encoding is as simple as:
145145
146-
iex> Car.new(color: :RED, top_speed: 125.3) |> Protobuf.JSON.encode()
146+
iex> Protobuf.JSON.encode(%Car{color: :RED, top_speed: 125.3})
147147
{:ok, ~S|{"color":"RED","topSpeed":125.3}|}
148148
149-
iex> Car.new(color: :GREEN) |> Protobuf.JSON.encode()
149+
iex> Protobuf.JSON.encode(%Car{color: :GREEN})
150150
{:ok, "{}"}
151151
152-
iex> Car.new() |> Protobuf.JSON.encode(emit_unpopulated: true)
152+
iex> Protobuf.JSON.encode(%Car{}, emit_unpopulated: true)
153153
{:ok, ~S|{"color":"GREEN","topSpeed":0.0}|}
154154
155155
"""
@@ -174,13 +174,13 @@ defmodule Protobuf.JSON do
174174
175175
## Examples
176176
177-
iex> Car.new(color: :RED, top_speed: 125.3) |> Protobuf.JSON.to_encodable()
177+
iex> Protobuf.JSON.to_encodable(%Car{color: :RED, top_speed: 125.3})
178178
{:ok, %{"color" => :RED, "topSpeed" => 125.3}}
179179
180-
iex> Car.new(color: :GREEN) |> Protobuf.JSON.to_encodable()
180+
iex> Protobuf.JSON.to_encodable(%Car{color: :GREEN})
181181
{:ok, %{}}
182182
183-
iex> Car.new() |> Protobuf.JSON.to_encodable(emit_unpopulated: true)
183+
iex> Protobuf.JSON.to_encodable(%Car{}, emit_unpopulated: true)
184184
{:ok, %{"color" => :GREEN, "topSpeed" => 0.0}}
185185
186186
"""

lib/protobuf/json/decode.ex

Lines changed: 24 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -59,11 +59,11 @@ defmodule Protobuf.JSON.Decode do
5959

6060
case Integer.parse(string) do
6161
{seconds, "s"} when seconds in @duration_seconds_range ->
62-
mod.new!(seconds: seconds)
62+
struct!(mod, seconds: seconds)
6363

6464
{seconds, "." <> nanos_with_s} when seconds in @duration_seconds_range ->
6565
case Utils.parse_nanoseconds(nanos_with_s) do
66-
{nanos, "s"} -> mod.new!(seconds: seconds, nanos: nanos * sign)
66+
{nanos, "s"} -> struct!(mod, seconds: seconds, nanos: nanos * sign)
6767
:error -> throw({:bad_duration, string, nanos_with_s})
6868
end
6969

@@ -74,80 +74,80 @@ defmodule Protobuf.JSON.Decode do
7474

7575
def from_json_data(string, Google.Protobuf.Timestamp = mod) when is_binary(string) do
7676
case Protobuf.JSON.RFC3339.decode(string) do
77-
{:ok, seconds, nanos} -> mod.new!(seconds: seconds, nanos: nanos)
77+
{:ok, seconds, nanos} -> struct!(mod, seconds: seconds, nanos: nanos)
7878
{:error, reason} -> throw({:bad_timestamp, string, reason})
7979
end
8080
end
8181

8282
def from_json_data(map, Google.Protobuf.Empty = mod) when map == %{} do
83-
mod.new!([])
83+
struct!(mod)
8484
end
8585

8686
def from_json_data(int, Google.Protobuf.Int32Value = mod),
87-
do: mod.new!(value: decode_scalar(:int32, :unknown_name, int))
87+
do: struct!(mod, value: decode_scalar(:int32, :unknown_name, int))
8888

8989
def from_json_data(int, Google.Protobuf.UInt32Value = mod),
90-
do: mod.new!(value: decode_scalar(:uint32, :unknown_name, int))
90+
do: struct!(mod, value: decode_scalar(:uint32, :unknown_name, int))
9191

9292
def from_json_data(int, Google.Protobuf.UInt64Value = mod),
93-
do: mod.new!(value: decode_scalar(:uint64, :unknown_name, int))
93+
do: struct!(mod, value: decode_scalar(:uint64, :unknown_name, int))
9494

9595
def from_json_data(int, Google.Protobuf.Int64Value = mod),
96-
do: mod.new!(value: decode_scalar(:int64, :unknown_name, int))
96+
do: struct!(mod, value: decode_scalar(:int64, :unknown_name, int))
9797

9898
def from_json_data(number, mod)
9999
when mod in [
100100
Google.Protobuf.FloatValue,
101101
Google.Protobuf.DoubleValue
102102
] and (is_float(number) or is_integer(number)) do
103-
mod.new!(value: number * 1.0)
103+
struct!(mod, value: number * 1.0)
104104
end
105105

106106
def from_json_data(bool, Google.Protobuf.BoolValue = mod) when is_boolean(bool) do
107-
mod.new!(value: decode_scalar(:bool, :unknown_field, bool))
107+
struct!(mod, value: decode_scalar(:bool, :unknown_field, bool))
108108
end
109109

110110
def from_json_data(string, Google.Protobuf.StringValue = mod) when is_binary(string) do
111-
mod.new!(value: decode_scalar(:string, :unknown_field, string))
111+
struct!(mod, value: decode_scalar(:string, :unknown_field, string))
112112
end
113113

114114
def from_json_data(bytes, Google.Protobuf.BytesValue = mod) when is_binary(bytes) do
115-
mod.new!(value: decode_scalar(:bytes, :unknown_field, bytes))
115+
struct!(mod, value: decode_scalar(:bytes, :unknown_field, bytes))
116116
end
117117

118118
def from_json_data(list, Google.Protobuf.ListValue = mod) when is_list(list) do
119-
mod.new!(values: Enum.map(list, &from_json_data(&1, Google.Protobuf.Value)))
119+
struct!(mod, values: Enum.map(list, &from_json_data(&1, Google.Protobuf.Value)))
120120
end
121121

122122
def from_json_data(struct, Google.Protobuf.Struct = mod) when is_map(struct) do
123123
fields =
124124
Map.new(struct, fn {key, val} -> {key, from_json_data(val, Google.Protobuf.Value)} end)
125125

126-
mod.new!(fields: fields)
126+
struct!(mod, fields: fields)
127127
end
128128

129129
def from_json_data(term, Google.Protobuf.Value = mod) do
130130
cond do
131131
is_nil(term) ->
132-
mod.new!(kind: {:null_value, :NULL_VALUE})
132+
struct!(mod, kind: {:null_value, :NULL_VALUE})
133133

134134
is_binary(term) ->
135-
mod.new!(kind: {:string_value, term})
135+
struct!(mod, kind: {:string_value, term})
136136

137137
is_integer(term) ->
138-
mod.new!(kind: {:number_value, term * 1.0})
138+
struct!(mod, kind: {:number_value, term * 1.0})
139139

140140
is_float(term) ->
141-
mod.new!(kind: {:number_value, term})
141+
struct!(mod, kind: {:number_value, term})
142142

143143
is_boolean(term) ->
144-
mod.new!(kind: {:bool_value, term})
144+
struct!(mod, kind: {:bool_value, term})
145145

146146
is_list(term) ->
147-
mod.new!(kind: {:list_value, from_json_data(term, Google.Protobuf.ListValue)})
147+
struct!(mod, kind: {:list_value, from_json_data(term, Google.Protobuf.ListValue)})
148148

149149
is_map(term) ->
150-
mod.new!(kind: {:struct_value, from_json_data(term, Google.Protobuf.Struct)})
150+
struct!(mod, kind: {:struct_value, from_json_data(term, Google.Protobuf.Struct)})
151151

152152
true ->
153153
throw({:bad_message, term, mod})
@@ -158,8 +158,8 @@ defmodule Protobuf.JSON.Decode do
158158
paths = String.split(data, ",")
159159

160160
cond do
161-
data == "" -> mod.new!(paths: [])
162-
paths = Enum.map(paths, &convert_field_mask_to_underscore/1) -> mod.new!(paths: paths)
161+
data == "" -> struct!(mod, paths: [])
162+
paths = Enum.map(paths, &convert_field_mask_to_underscore/1) -> struct!(mod, paths: paths)
163163
true -> throw({:bad_field_mask, data})
164164
end
165165
end
@@ -187,7 +187,7 @@ defmodule Protobuf.JSON.Decode do
187187
|> message_mod.encode()
188188
end
189189

190-
mod.new!(type_url: type_url, value: encoded)
190+
struct!(mod, type_url: type_url, value: encoded)
191191
end
192192

193193
def from_json_data(data, module) when is_map(data) and is_atom(module) do

lib/protobuf/protoc/cli.ex

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -57,10 +57,10 @@ defmodule Protobuf.Protoc.CLI do
5757
Protobuf.Protoc.Generator.generate(ctx, desc)
5858
end)
5959

60-
Google.Protobuf.Compiler.CodeGeneratorResponse.new(
60+
%Google.Protobuf.Compiler.CodeGeneratorResponse{
6161
file: files,
6262
supported_features: supported_features()
63-
)
63+
}
6464
|> Protobuf.encode_to_iodata()
6565
|> IO.binwrite()
6666
end

0 commit comments

Comments
 (0)