Protobuf behaviour (protobuf v0.11.0) View Source
protoc
should always be used to generate code instead of writing the code by hand.
By use
this module, macros defined in Protobuf.DSL
will be injected. Most of thee macros
are equal to definition in .proto files.
defmodule Foo do
use Protobuf, syntax: :proto3
defstruct [:a, :b]
field :a, 1, type: :int32
field :b, 2, type: :string
end
Your Protobuf message(module) is just a normal Elixir struct. Some useful functions are also injected, see "Callbacks" for details. Examples:
foo1 = Foo.new!(%{a: 1})
foo1.b == ""
bin = Foo.encode(foo1)
foo1 == Foo.decode(bin)
Except functions in "Callbacks", some other functions may be defined:
- Extension functions when your Protobuf message use extensions. See
Protobuf.Extension
for details.put_extension(struct, extension_mod, field, value)
get_extension(struct, extension_mod, field, default \ nil)
Link to this section Summary
Callbacks
Decodes a Protobuf binary into a struct.
Encodes the given struct into to a Protobuf binary.
Builds a blank struct with default values. This and other "new" functions are
preferred than raw building struct method like %Foo{}
.
Builds and updates the struct with passed fields.
Returns nil
or a transformer module that implements the Protobuf.TransformModule
behaviour.
Functions
Decodes the given binary data interpreting it as the Protobuf message module
.
Encodes the given Protobuf struct into a binary.
Encodes the given Protobuf struct into iodata.
Returns the unknown fields that were decoded but were not understood from the schema.
Loads extensions modules.
Link to this section Callbacks
Specs
Decodes a Protobuf binary into a struct.
Errors may be raised if there's something wrong in the binary.
Specs
Encodes the given struct into to a Protobuf binary.
Errors may be raised if there's something wrong in the struct.
If you want to encode to iodata instead of to a binary, use encode_to_iodata/1
.
Specs
new() :: struct()
Builds a blank struct with default values. This and other "new" functions are
preferred than raw building struct method like %Foo{}
.
In proto3, the zero values are the default values.
Specs
Builds and updates the struct with passed fields.
This function will:
- Recursively call
new/1
for embedded fields - Create structs using
struct/2
for keyword lists and maps - Create the correct struct if passed the wrong struct
- Call
new/1
for each element in the list for repeated fields
Examples
MyMessage.new(field1: "foo")
#=> %MyMessage{field1: "foo", ...}
MyMessage.new(field1: [field2: "foo"])
#=> %MyMessage{field1: %MySubMessage{field2: "foo"}}
MyMessage.new(field1: %WrongStruct{field2: "foo"})
#=> %MyMessage{field1: %MySubMessage{field2: "foo"}}
MyMessage.new(repeated: [%{field1: "foo"}, %{field1: "bar"}])
#=> %MyMessage{repeated: [%MyRepeated{field1: "foo"}, %MyRepeated{field1: "bar"}]}
Specs
Similar to new/1
, but use struct!/2
to build the struct, so
errors will be raised if unknown keys are passed.
Specs
transform_module() :: module() | nil
Returns nil
or a transformer module that implements the Protobuf.TransformModule
behaviour.
This function is overridable in your module.
Link to this section Functions
Specs
Decodes the given binary data interpreting it as the Protobuf message module
.
It's preferrable to use the message's decode/1
function. For a message MyMessage
:
MyMessage.decode(<<...>>)
#=> %MyMessage{...}
This function raises an error if anything goes wrong with decoding.
Examples
Protobuf.decode(<<...>>, MyMessage)
#=> %MyMessage{...}
Protobuf.decode(<<"bad data">>, MyMessage)
#=> ** (Protobuf.DecodeError) ...
Specs
Encodes the given Protobuf struct into a binary.
If you want to encode to iodata instead, see encode_to_iodata/1
.
Examples
struct = MyMessage.new()
Protobuf.encode(struct)
#=> <<...>>
Specs
Encodes the given Protobuf struct into iodata.
Examples
struct = MyMessage.new()
Protobuf.encode_to_iodata(struct)
#=> [...]
Specs
get_unknown_fields(struct()) :: [unknown_field] when unknown_field: {field_number :: integer(), Protobuf.Wire.Types.wire_type(), value :: any()}
Returns the unknown fields that were decoded but were not understood from the schema.
In Protobuf, you can decode a payload (for the same message) encoded with a different version of the schema for that message. This can result in, for example, the payload containing fields that cannot be decoded correctly because they're not present in the schema used for decoding. These fields are skipped, but in some cases you might wish to preserve them in order to re-encode them, log them, or other. A common case is having to do "round-trips" with messages: you decode a payload, update the resulting message somehow, and re-encode it for future use. In these cases, you would probably want to re-encode the unknown fields to maintain symmetry.
The returned value of this function is a list of {field_number, field_value}
tuples where
field_number
is the number of the unknown field in the schema used for its encoding and
field_value
is its value. The library does not make any assumptions on the value of the
field since it can't know for sure. This means that, for example, it can't properly decode
an integer as signed or unsigned. The only guarantee is that the unknown fields are re-encoded
correctly.
The reason why these fields need to be accessed through this function is that the way they are stored in the struct is private.
Examples
Imagine you have this Protobuf schema:
message User {
string email = 1;
}
You encode this:
payload = Protobuf.encode(User.new!(email: "user@example.com))
#=> <<...>>
Now, you try to decode this payload using this schema instead:
message User {
string full_name = 2;
}
In this case, this function will return the decoded unknown field:
message = User.decode(<<...>>) Protobuf.get_unknown_fields(message) #=> [{_field_number = 1, _wire_type = 3, "user@example.com}]
Specs
load_extensions() :: :ok
Loads extensions modules.
This function should be called in your application's Application.start/2
callback,
as seen in the example below, if you wish to use extensions.
Example
@impl Application
def start(_type, _args) do
Protobuf.load_extensions()
Supervisor.start_link([], strategy: :one_for_one)
end