Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

protobuf text format parsing maps

This answer clearly shows some examples of proto text parsing, but does not have an example for maps.

If a proto has:

map<int32, string> aToB

I would guess something like:

aToB {
    123: "foo"
}

but it does not work. Does anyone know the exact syntax?

like image 488
lf215 Avatar asked Dec 01 '16 04:12

lf215


2 Answers

I initially tried extrapolating from an earlier answer, which led me astray, because I incorrectly thought multiple k/v pairs would look like this:

aToB {         # (this example has a bug)
    key: 123
    value: "foo"
    key: 876        # WRONG!
    value: "bar"    # NOPE!
}

That led to the following error:

 libprotobuf ERROR: Non-repeated field "key" is specified multiple times.

Proper syntax for multiple key-value pairs:

(Note: I am using the "proto3" version of the protocol buffers language)

aToB {
    key: 123
    value: "foo"
}
aToB {
    key: 876        
    value: "bar"    
}

The pattern of repeating the name of the map variable makes more sense after re-reading this relevant portion of the proto3 Map documentation, which explains that maps are equivalent to defining your own "pair" message type and then marking it as "repeated".


A more complete example:

proto definition:

syntax = "proto3";
package myproject.testing;

message UserRecord {
  string handle = 10;
  bool paid_membership = 20;
}

message UserCollection {
  string description = 20;
  // HERE IS THE PROTOBUF MAP-TYPE FIELD:
  map<string, UserRecord> users = 10;
}

message TestData {
  UserCollection user_collection = 10;
}

text format ("pbtxt") in a config file:

user_collection {
  description = "my default users"
  users {
    key: "user_1234"
    value {
      handle: "winniepoo"
      paid_membership: true
    }
  }
  users {
    key: "user_9b27"
    value {
      handle: "smokeybear"
    }
  }
}

C++ that would generate the message content programmatically

myproject::testing::UserRecord user_1;
user_1.set_handle("winniepoo");
user_1.set_paid_membership(true);
myproject::testing::UserRecord user_2;
user_2.set_handle("smokeybear");
user_2.set_paid_membership(false);

using pair_type =
    google::protobuf::MapPair<std::string, myproject::testing::UserRecord>;

myproject::testing::TestData data;
data.mutable_user_collection()->mutable_users()->insert(
    pair_type(std::string("user_1234"), user_1));
data.mutable_user_collection()->mutable_users()->insert(
    pair_type(std::string("user_9b27"), user_2));
like image 151
pestophagous Avatar answered Oct 02 '22 12:10

pestophagous


The text format is:

aToB {
    key: 123
    value: "foo"
}
like image 22
lf215 Avatar answered Oct 02 '22 14:10

lf215