Maps
As of version 4.0.0, Embedded Proto supports map fields. A map is declared in the proto file as in any other protobuf implementation. Like repeated fields, a map has a fixed number of entries in Embedded Proto. You set the number with the maxLength option. When the key is a string, also set its maximum length with keyMaxLength. When the value is a string or bytes field, set valueMaxLength. Let us take a look at an example:
import "embedded_proto_options.proto";
message Device
{
map<string, int32> readings = 1 [(EmbeddedProto.options) = { maxLength: 8, keyMaxLength: 16 }];
}Here the options are written together between braces. This is the same as writing (EmbeddedProto.options).maxLength = 8 and (EmbeddedProto.options).keyMaxLength = 16 separately. When you leave the options out, the sizes become template parameters of the message, in this case Device<8, 16>. The options can also be set from an options file.
On the wire, a map is a repeated field of entry messages, each holding a key and a value. Embedded Proto stores it in exactly this way, as an array of entries. The serialized bytes are identical to those of the Google implementation.
Usage of maps
The generated code gives the field the interface you expect from a map. A working example could look like this:
Device device;
// Add or update entries. The function returns ARRAY_FULL when the map
// is full and the key is new, or when the key does not fit.
device.set_readings("temperature", 21);
device.set_readings("humidity", 60);
// Look up a value. For a key that is not present the default value is
// returned, zero in this case. Use has_readings() to tell the two apart.
if(device.has_readings("temperature"))
{
const int32_t temperature = device.get_readings("temperature");
}
// Or get the value together with an error code. This is the only form
// available for bytes and message values.
int32_t humidity = 0;
auto status = device.get_readings("humidity", humidity);
// The number of entries and the maximum.
const uint32_t n = device.readings_size();
const uint32_t max_n = device.readings_max_size();
// Remove one entry, or all of them.
device.remove_readings("humidity");
device.clear_readings();For a key of an integer type, the functions take that type instead of a const char*. A lookup walks the entries from the back, so it takes time linear in the number of entries. The entries themselves are accessible as with a repeated field, using readings(index), mutable_readings(index) and add_readings().
Please note that entries received from the wire are stored as they are. When a peer sends the same key twice, both entries are kept and a lookup returns the last one. When a peer sends more entries than the map holds, or a key or value longer than the maximum, deserialization returns ARRAY_FULL.
Is the map too large to store in the message? A map can also be streamed through callbacks with the callbackStorage option, in which case no entries are stored at all. See callback storage.