Any
As of version 4.0.0, Embedded Proto supports the well known type google.protobuf.Any. An Any carries a message of a type which is not fixed by your proto file: a string naming the message type, and the serialized bytes of a message of that type. Let us take a look at an example:
import "google/protobuf/any.proto";
message Envelope
{
uint32 sequence = 1;
google.protobuf.Any details = 2;
}The generator emits google/protobuf/any.h next to your own headers. It holds the message google::protobuf::Any, generated from the Google definition like any other message. That definition is a string field named type_url and a bytes field named value. The serialized bytes are identical to those of the Google implementation.
Like a string or bytes field, both fields of the Any have a fixed length in Embedded Proto. When you do not set a length, the two become template parameters of the message holding the Any, and of every message holding that one. The type url comes first:
Envelope<40, 64> envelope;You can also fix the lengths for every Any in your project from an options file. Key the entry by the full name of the Google message:
{
"google.protobuf.Any": {
"type_url": { "maxLength": 40 },
"value": { "maxLength": 64 }
}
}The value must be able to hold the largest message you pack. The max_serialized_size() function of that message gives you the bound.
The type url
The type url names the message type held in the value. The Google implementation writes it as type.googleapis.com/ followed by the full name of the message type, package and enclosing messages included. Every implementation only looks at what follows the last slash, nothing is fetched from that address. To fill it without typing the name yourself, every generated message carries the constant MESSAGE_FULL_NAME. For a message Sensor in package weather this is "weather.Sensor".
Packing and unpacking
To pack a message, serialize it into a buffer and hand the bytes to the Any together with the type url:
Sensor sensor;
sensor.set_id(7);
::EmbeddedProto::WriteBufferFixedSize<Sensor::max_serialized_size()> payload;
sensor.serialize(payload);
Envelope<40, 64> envelope;
envelope.mutable_details().mutable_type_url() = "type.googleapis.com/weather.Sensor";
envelope.mutable_details().mutable_value().set(::EmbeddedProto::const_bytes_view{payload.get_data(), payload.get_size()});The set function returns ARRAY_FULL when the payload does not fit in the value. To unpack, check the name behind the last slash of the type url and read the value with a buffer of its own:
const auto& details = envelope.get_details();
const char* const name = strrchr(details.type_url(), '/');
if((nullptr != name) && (0 == strcmp(name + 1, Sensor::MESSAGE_FULL_NAME)))
{
const auto& value = details.get_value();
::EmbeddedProto::ReadBufferFixedSize<64> payload;
memcpy(payload.get_data(), value.get_const(), value.get_length());
payload.set_bytes_written(value.get_length());
Sensor sensor;
sensor.deserialize(payload);
}Please note that when a peer sends a type url or a value longer than the maximum, deserialization of the enclosing message returns ARRAY_FULL. An Any works in a nested message, a repeated field and a oneof like any other message field.