I'm wondering if it is possible to use Google Protocol Buffers' enum constants as a field number of other messages, like
enum Code {
FOO = 100;
BAR = 101;
}
message Message {
required string foo = FOO;
}
This code doesn't work because FOO's type is enum Code and only a number can be used as a field number.
I am trying to build polymorphic message definitions like this animal example, that defines Cat = 1; in enum Type and required Cat animal = 100; as a unique extension number.
I thought it'd be nice to do
message Message {
required string foo = FOO.value;
}
, so that I can ensure the uniqueness of the extension field number without introducing another magic number.
So the question: is it possible to refer an enum's integer value in the protocol buffer language?
No, there is no way to do this. Sorry.
BTW, two enumerants of the same enum type can actually have the same numeric value, so defining these values in an enum does not actually ensure uniqueness.
Related
I want to understand if the messages bellow are compatible from the perspective of protobuf and serialization/deserialization.
message HelloReply {
string message = 1;
string personalized_message = 2;
}
message HelloReply {
string personalized_message = 2;
string message = 1;
}
Does the order matter for compatibility in any situation?
The textual order is largely irrelevant, although it may impact some code generation tooling - but most languages don't care about declaration order, so even that: won't matter. The fields are still defined semantically equivalent - the numbers match the existing meaning (name) and type. It is the number that is the determining feature in identifying a field.
At the protocol level:
parsers must allow fields in any order
serializers should (but not must) write fields in ascending numerical field order
I want to be able to supply a pre-instantiated message by name rather than populating it from scratch. For example, given the following schema:
message Animal {
required int32 num_legs = 1;
required int32 num_eyes = 2;
}
message Zoo {
repeated Animal animals;
}
I want to be able quickly to define a Zoo in my config file by choosing from a set of known animals:
// config.json
zoo: {
animals: [snake, bird]
}
where snake and bird are already defined:
// animals.json
bird: {
num_legs: 2
num_eyes: 2
}
snake: {
num_legs: 0
num_eyes: 2
}
What's the most elegant way to do this?
The protobuf API has methods to convert protobuf⬌JSON. For C++ you can use util::JsonStringToMessage, other languages have their API versions too (you didn't specify a language). Wrap this in a simple helper function and use your language's multi-line string constant syntax to embed the message in JSON format directly into your source.
To get your named predefined messages, use a language that has string interpolation. (Not native to C++, unfortunately, but here is a SO answer talking about ways you might do it.)
Is it (practically) possible to change the type name of a protobuf message type (or enum) without breaking communications?
Obviously the using code would need to be adpated to re-compile. The question is if old clients that use the same structure, but the old names, would continue to work?
Example, base on the real file:
test.proto:
syntax = "proto3";
package test;
// ...
message TestMsgA {
message TestMsgB { // should be called TestMsgZZZ going forward
// ...
enum TestMsgBEnum { // should be called TestMsgZZZEnum going forward
// ...
}
TestMsgBEnum foo = 1;
// ...
}
repeated TestMsgB bar = 1;
// ...
}
Does the on-the-wire format of the protobuf payload change in any way if type or enum names are changed?
If you're talking about the binary format, then no: names don't matter and will not impact your ability to load data; For enums, only the integer value is stored in the payload. For fields, only the field-number is stored.
Obviously if you swap two names, confusion could happen, but: it should load as long as the structure matches.
If you're talking about the JSON format, then it may matter.
I am using protocol buffers defined like this:
message Index {
message albums {
repeated string name = 1;
}
map<string, albums> artists_albums= 1;
map<int32, albums> year_albums = 2;
}
It generates go code like this:
type Index struct {
ArtistsAlbums map[string]*IndexAlbums
YearAlbums map[int32]*IndexAlbums
}
How can I make it generate map values of type IndexAlbums instead of *IndexAlbums?
If you use gogoprotobuf then there is an extension that will allow that
map<string, albums> artists_albums = 1 [(gogoproto.nullable) = false];
With regular goprotobuf I don't believe there is a way.
nullable, if false, a field is generated without a pointer (see warning below).
Warning about nullable: According to the Protocol
Buffer specification, you should be able to tell whether a field is
set or unset. With the option nullable=false this feature is lost,
since your non-nullable fields will always be set. It can be seen as a
layer on top of Protocol Buffers, where before and after marshalling
all non-nullable fields are set and they cannot be unset.
I've run into a use case where I'd like to move an enum declared inside a protocol buffer message to outside the message so that other messages van use the same Enum.
ie, I'm wondering if there are any issues moving from this
message Message {
enum Enum {
VALUE1 = 1;
VALUE2 = 2;
}
optional Enum enum_value = 1;
}
to this
enum Enum {
VALUE1 = 1;
VALUE2 = 2;
}
message Message {
optional Enum enum_value = 1;
}
Would this cause any issues de-serializing data created with the first protocol buffer definition into the second?
It doesn't change the serialization data at all - the location / name of the enums are irrelevant for the actual data, since it just stores the integer value.
What might change is how some languages consume the enum, i.e. how they qualify it. Is it X.Y.Foo, X.Foo, or just Foo. Note that since enums follow C++ naming/scoping rules, some things (such as conflicts) aren't an issue: but it may impact some languages as consumers.
So: if you're the only consumer of the .proto, you're absolutely fine here. If you have shared the .proto with other people, it may be problematic to change it unless they are happy to update their code to match any new qualification requirements.