Protocol buffers and enums combinations?
In Protobufs, an enum-typed field is only allowed to have one of the exact numeric values specified in the enum. That is to say, you cannot use an enum-typed field as a bitfield. If you want a bitfield, you need to use an integer type like int32
. This rule actually applies even in languages that have numeric enum types, like C++ -- if an enum-typed protobuf field read from the wire has an invalid value, it will be treated like an unknown field and thus hidden.
If you switch to integers, you of course now have the problem of how to declare flag values. Unfortunately Protobufs provides no good way to define constants. As you suggested in your self-answer, you can use a dummy enum definition as a hack, but note that the numeric value won't necessarily be available in all languages. It works in C++ and Python since they use numeric enums (and apparently C# too?). In Java, Protobuf enums have a .getNumber()
method which you can use to get the numeric value; otherwise, normal Java enums are not numeric.
(Aside: I'm the author of most of Google's open source Protobuf code. I'm also the author of Cap'n Proto, a newer non-Google project aimed at replacing Protobufs. Among other advantages, Cap'n Proto supports defining constants in schema files. But, as of this writing C# support is not ready yet (though being worked on!).)
I found a solution (sort of)
need an int holder.
message Foo {
enum Flags {
FLAG1 = 0x01;
FLAG2 = 0x02;
FLAG3 = 0x04;
}
// Bitwise-OR of Flags.
optional uint32 flags = 1;
- Mmm, Is it the only solution ?
You can use message instead of enums, and use bool type for the flags you need.
Here's an example for a simple Alarm Clock schema where it can be set for multiple days in the week:
message Alarm {
uint32 hour = 1;
uint32 minute = 2;
bool repeat = 3;
DaysOfWeek daysOfWeek = 4;
message DaysOfWeek {
bool sunday = 1;
bool monday = 2;
bool tuesday = 3;
bool wednesday = 4;
bool thursday = 5;
bool friday = 6;
bool saturday = 7;
}
}
If you don't need to squeeze out every last inch of efficiency (hint: you probably don't), then just use an array of enum values.
message Msg {
// ...
enum Code
{
MSG = 0;
FILE = 1;
APPROVE = 2;
ACK = 3;
ERROR_SENDING = 4;
WORLD = 5;
}
repeated Code codes = 5;
}
Much later edit: The official protobuf docs recommend you reserve an enum entry equal to 0 to mean something like "unknown". It's really targetted at enums that are used as non-repeated values (because in proto3 there's no difference between the 0 enum value and unset) but worth following for all enums. In this case, that means you'd replace the above with UNKNOWN = 0
, MSG = 1
, etc.