Google::ProtocolBuffers::Dynamic - fast and complete protocol buffer implementation
version 0.41
$dynamic = Google::ProtocolBuffers::Dynamic->new; $dynamic->load_string("person.proto", <<'EOT'); syntax = "proto2"; package humans; message Person { required string name = 1; required int32 id = 2; optional string email = 3; } EOT $dynamic->map({ package => 'humans', prefix => 'Humans' }); # encoding/decoding $person = Humans::Person->decode("\x0a\x03foo\x10\x1f"); $person = Humans::Person->decode_json('{"id":31,"name":"John Doe"}'); $bytes = Humans::Person->encode($person); $bytes = Humans::Person->encode_json($person); # field accessors $person = Humans::Person->new; $person->set_id(77); $id = $person->get_id;
See also protoc-gen-perl-gpd for ahead-of-time generation.
This module uses Google C++ Protocol Buffers parser and the uPB serialization/deserialization library to provide a fast and complete mapping of Protocol Buffers for Perl.
There is builtin support for creating gRPC clients for RPC services, using Grpc::XS as transport.
Protocol Buffers objects are normal blessed hashes, with auto-generated accessors for message fields. Accessing the hash directly is possible but not recommended (it will skip validation, it won't respect the default value option of fields, it won't respect oneof semantics, ...).
The following section outlines how Protocol Buffer sematics are mapped to Perl; it also doubles as an API reference for generated message classes.
In general, there is no direct correspondence between Protocol Buffer packages and Perl packages (each Protocol Buffer message can be mapped independently to an arbitrary Perl package).
That being said, it is simpler to map each Protocol Buffer package to a Perl package prefix, and use the automated package mapping (when pb_test is mapped to Perl::Test, pb_test.Message becomes Perl::Test::Message, pb_test.Message.SomeEnum becomes Perl::Test::Message::SomeEnum, ...).
pb_test
Perl::Test
pb_test.Message
Perl::Test::Message
pb_test.Message.SomeEnum
Perl::Test::Message::SomeEnum
Each Protocol Buffer message is mapped to a generated Perl class.
Message classes don't have a parent class (but expose the methods documented in Google::ProtocolBuffers::Dynamic::Message, so you can think of them as interface implementations, if you want), and provide the field accessors documented below.
Message classes should not be subclassed: if you thread carefully you might be able to get away with it, but in general they won't work correctly (for example, overridden constructors/accessors won't be called during serialization/deserialization).
Unless explicitly mapped, nested messages will be mapped as nested packages (e.g. if package.Foo is mapped to MyPack::Foo, package.Foo.Bar will be mapped to MyPack::Foo::Bar.
package.Foo
MyPack::Foo
package.Foo.Bar
MyPack::Foo::Bar
Each field is mapped to a set of accessors (documented below).
For each field, a constant with the field number is exposed to Perl. For example the field optional string foo = 7 will result in a constant equivalent to use constant FOO_FIELD_NUMBER => 7.
optional string foo = 7
use constant FOO_FIELD_NUMBER => 7
On Perls with 32-bit integers, int64/uint64 fields with values outside the representable range will be returned as Math::BigInt objects and can be set the same way. On Perls with 64-bit integers, Math::BigInt objects are accepted by setters but not returned by getters (unless "use_bigints" is used).
int64
uint64
For a field named foo the message class will have a getter ($msg->get_foo), a setter ($msg->set_foo($value)) a clear method ($msg->clear_foo) and an existence check ($msg->has_foo).
foo
$msg->get_foo
$msg->set_foo($value)
$msg->clear_foo
$msg->has_foo
The getter returns the default value for the field (0 for numeric fields, '' for string fields, undef for message fields) if the field is not set/has been cleared.
0
''
undef
The setter performs coercion and type checks; for example setting an integer field to a floating point value will truncate the decimal part.
Setting a message field will take ownership of the passed-in hash/object.
The setters for enum fields check that the passed-in value is one of the valid enum values, unless "check_enum_values" is false.
For a field named foo the message class will have an item getter ($msg->get_foo($index)), an item setter ($msg->set_foo($index, $value)) and appender ($msg->add_foo($value)).
$msg->get_foo($index)
$msg->set_foo($index, $value)
$msg->add_foo($value)
$msg->foo_size returns the number of elements in the list, $msg->get_foo_list and $msg->set_foo_list act as getter/setter for the whole list, taking/returning an array reference.
$msg->foo_size
$msg->get_foo_list
$msg->set_foo_list
For a field named foo the message class will have an item getter ($msg->get_foo($key)) and an item setter ($msg->set_foo($key, $value)).
$msg->get_foo($key)
$msg->set_foo($key, $value)
$msg->get_foo_map and $msg->set_foo_map act as getter/setter for the whole map, taking/returning a hash reference.
$msg->get_foo_map
$msg->set_foo_map
The map<key, value> syntax is only available for proto3, see see "implicit_maps" to emulate map support when using proto2.
map<key, value>
proto3
proto2
Enumeration values are passed around as integers.
As a convenience, each enumeration value is mapped to a Perl constant; for example:
enum Foo { BAR = 1; BAZ = 2; }
will result in constants equivalent to
use constant { BAR => 1, BAZ => 2, };
If "check_enum_values" is true (the default), trying to encode a message containing an invalid enum value will result in an error, trying to decode it will ignore the invalid value. If "check_enum_values" is false, invalid enum values are passed through unchanged.
Oneof fields don't generate any specific accessors, however calling the setter for one of the contained fields will clear the other fields that are members of the same oneof.
Extension fields are treated like other scalar/repeated fields, except that accessor names are generated using the fully-qualified name of the extension.
For example
package test; // ... extend Message1 { optional int32 value = 102; } message Message2 { extend Message1 { optional Message2 extension2 = 101; } optional int32 value = 1; }
will create (scalar, in this case) accessors for fields named test_value and test_message2_extension2.
test_value
test_message2_extension2
In addition to per-field accessors, there is a set of generic extension accessors (documented in "EXTENSION METHODS" in Google::ProtocolBuffers::Dynamic::Message).
Each service is mapped to a generated Perl class, with each method mapped to a Perl method.
Google::ProtocolBuffers::Dynamic does not provide an RPC implementation, but supports generating a gRPC client using Grpc::XS (other implementations might be provided in the future).
Google::ProtocolBuffers::Dynamic
In addition, there is a noop service mapping mode that exposes introspection information to simplify the mapping of external RPC implementation on top of Google::ProtocolBuffers::Dynamic.
noop
The exact interface of mapped methods depends on the underlying RPC implementation (for example, for Grpc::XS, the return value is a subclass of Grpc::Client::AbstractCall) and whether the method uses client/server streaming.
All mapped entities provide access to an introspection object that describes the Protocol Buffers object definition.
Each mapped message has a message_descriptor class method returning a MessageDef object.
message_descriptor
Each mapped enum has an enum_descriptor class method returning an EnumDef object.
enum_descriptor
Each mapped service has a service_descriptor class method returning a ServiceDef object.
service_descriptor
This section describes methods used to load/map Protocol Buffer messages, see above for the API of mapped messages.
The normal usage pattern is:
"map" is a wrapper around the various map_* methods and "resolve_references", so there should be no reason for using those directly.
map_*
$dynamic = Google::ProtocolBuffers::Dynamic->new; $dynamic = Google::ProtocolBuffers::Dynamic->new($root_directory);
When specified, $root_directory is used as base for relative paths in load_file.
$root_directory
load_file
$dynamic->load_file($file_path);
Loads the specified file, searching for it in the path passed to the constructor.
$dynamic->load_string($file_name, $string);
Parses message definitions from a string. The $file_name parameter is only used to report errors, and can be the empty string.
$file_name
$dynamic->load_serialized_string($string);
Parses message definitions from serialized descriptor data in the format produced by protoc --descriptor_set_out option.
protoc
--descriptor_set_out
# the 'options' key is optional $dynamic->map( # uses map_package_prefix { pb_prefix => $pb_prefix,prefix => $perl_prefix, options => $options }, # uses map_message_prefix { message => $pb_message, prefix => $perl_prefix, options => $options }, # uses map_package { package => $pb_package, prefix => $perl_prefix, options => $options }, # uses map_message { message => $pb_message, to => $perl_package, options => $options }, # uses map_service { service => $pb_enum, to => $perl_package, options => { client_services => $mapping_mode, # other options }, );
Applies the mappings in order and then calls "resolve_references".
Order is important because package mappings skip types already mapped by previous mappings, but message/enum mappings throw an error if the type has already been mapped.
For example, given:
package test; message Foo { } message Bar { }
the following mapping:
$dynamic->map( { message => 'test.Foo', to => 'SomePackage::Foo' }, { package => 'test' prefix => 'OtherPackage' }, );
maps test.Foo to SomePackage::Foo and test.Bar to OtherPackage::Bar whereas
test.Foo
SomePackage::Foo
test.Bar
OtherPackage::Bar
$dynamic->map( { package => 'test' prefix => 'OtherPackage' }, { message => 'test.Foo', to => 'SomePackage::Foo' }, );
throws an error because test.Foo has already been mapped (to OtherPackage::Foo) by the first mapping.
OtherPackage::Foo
$dynamic->map_package_prefix($pb_prefix, $perl_prefix); $dynamic->map_package_prefix($pb_prefix, $perl_prefix, $options);
Finds all types contained in ProtocolBuffers packages having the given prefix and (recursively) maps them under the specified Perl package prefix. It silently skips any already mapped types.
$dynamic->map_message_prefix($pb_message, $perl_prefix); $dynamic->map_message_prefix($pb_message, $perl_prefix, $options);
Maps the specified message (recursively) under the Perl package prefix, using the full package name of the message. It silently skips any already mapped types (although it will still recurse in to them).
In particular, this is quite useful to automatically map a message that uses messages types defined in other packages.
You might also want to map a required message to a specified package and then make sure other messages used by that message are mapped elsewhere. This can be achieved by mapping with a prefix after mapping the message (since "map_message_prefix" skips already-mapped stuff).
$dynamic->map_package($pb_package, $perl_prefix); $dynamic->map_package($pb_package, $perl_prefix, $options);
Finds all types contained in the specified package and (recursively) maps them under the specified Perl package prefix. It silently skips any already mapped types.
$dynamic->map_message($pb_message, $perl_package); $dynamic->map_message($pb_message, $perl_package, $options);
Maps the specified message to the specified Perl package and (recursively) all contained types to inner packages. It throws an error if the specified message has already been mapped but silently skips any already mapped inner types.
$dynamic->map_enum($pb_enum, $perl_package); $dynamic->map_enum($pb_enum, $perl_package, $options);
Maps the specified enumeration to the specified Perl package. It throws an error if the enumeration has already been mapped.
$dynamic->map_service($pb_service, $perl_package, options => { client_services => $mapping_mode, # other options });
Maps the specified service to the specified Perl package. It throws an error if the service has already been mapped.
$dynamic->resolve_references;
Called implicitly by "map", must be called when using the lower-level mapping functions. Resolves any message cross-references (e.g. fields with message or enumeration types).
Can be passed to the various mapping methods.
proto3 provides a special map<key, value> syntax to define map fields:
map<key-type, value-type> field = 1;
which is equivalent to the following proto2 definition
message FieldEntry { optional key-type key = 1; optional value-type value = 2; } repeated FieldEntry field = 1;
Google::ProtocolBuffers::Dynamic can detect when a map-like structure has been defined using the proto2 syntax above and provide the same semantics as a proto3 map (i.e. it will accept a Perl hash when encoding and produce a Perl hash when decoding).
When implicit_maps is enabled, messages with the following properties:
implicit_maps
Entry
optional
key
value
oneof
will be marked as map entries. Those rules do not check all the restrictions that are in place for a proto3 map, and they might be made stricter in the future.
Enabled by default on Perls with 32-bit integers, disabled by default on Perls with 64-bit integers.
When enabled, values that don't fit in a 32-bit integer are returned as Math::BigInt objects.
Defaults to perl.
perl
It controls how boolean values are mapped in Perl. Accepted values are:
Maps true to 1 and false to "".
true
1
false
""
Maps true to 1 and false to 0.
Enabled by default.
When enabled, checks that all required fields are present (for both encoding and decoding).
Disabled by default, it can't be enabled for proto3.
When disabled, if the value of a field is equal to its default, the field is not emitted during serialization, whether the value was explicitly set or not.
When enabled, and a value was explicitly set for the field, the field is always emitted.
Disabled by default, it can't be enabled for proto2.
Same as encode_defaults. The only reason to enable this is as an hack to emulate proto3 field presence support.
encode_defaults
Disabled by default.
When enabled, explicitly sets all missing scalar fields (but not oneof members) to their default value when decoding.
When enabled, invalid enum values throw an error in getters/setters/encoding and are replaced with the default value for that enum when decoding.
Controls the generation of generic extension methods. Only disable when there is a field named extension.
extension
Defaults to get_and_set.
get_and_set
It controls the naming and interface of getters/setters created for message fields. Accepted values are:
Getter is prefixed with get_, setter with set_.
get_
set_
Getter does not have any prefix, setter with set_.
Generates a single method without a prefix that acts as a setter when a value is passed, as a getter otherwise.
Defaults to disable.
disable
Silently ignore all service definitions.
Only provide introspection information for services (see "INTROSPECTION").
Generate a client implementation using Grpc::XS.
Return blessed objects when decoding. When disabled, plain hashes are returned.
Throws an error when a non-overloaded reference is passsed as the value of a non-message field.
Not available for Perl 5.12 or older.
When a field has the incorrect value, sometimes serialization performs a coercion, sometimes it throws an error, but it should always be an error.
Unknown fields are discarded on deserialization.
Proto3 support is only partial (support for well-known types, such as Any and Duration is missing).
See also the TODO
protoc-gen-perl-gpd
Google Protocol Buffers page
uPB serialization/deserialization library
Mattia Barbon <mattia@barbon.org>
This software is copyright (c) 2015-2016 by Mattia Barbon.
This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself.
To install Google::ProtocolBuffers::Dynamic, copy and paste the appropriate command in to your terminal.
cpanm
cpanm Google::ProtocolBuffers::Dynamic
CPAN shell
perl -MCPAN -e shell install Google::ProtocolBuffers::Dynamic
For more information on module installation, please visit the detailed CPAN module installation guide.