You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@mesos.apache.org by qi...@apache.org on 2018/03/14 03:33:10 UTC
[2/5] mesos git commit: Added protobuf map support to stout
JSON<->protobuf conversion.
Added protobuf map support to stout JSON<->protobuf conversion.
Map is a feature of proto2 syntax, but it can only be compiled
with 3.0.0+ protobuf compiler, see the following discussion for
details:
https://groups.google.com/forum/#!topic/protobuf/p4WxcplrlA4
We have already upgraded the compiler from 2.6.1 to 3.3.0 in
MESOS-7228. This patch adds map support in the json <-> protobuf
conversion in stout.
Review: https://reviews.apache.org/r/59987/
Project: http://git-wip-us.apache.org/repos/asf/mesos/repo
Commit: http://git-wip-us.apache.org/repos/asf/mesos/commit/5b226140
Tree: http://git-wip-us.apache.org/repos/asf/mesos/tree/5b226140
Diff: http://git-wip-us.apache.org/repos/asf/mesos/diff/5b226140
Branch: refs/heads/master
Commit: 5b2261409e2b391d9182c5579e1df481c7f0779f
Parents: 61e7765
Author: Qian Zhang <zh...@gmail.com>
Authored: Mon Jul 10 15:21:55 2017 +0800
Committer: Qian Zhang <zh...@gmail.com>
Committed: Wed Mar 14 08:18:53 2018 +0800
----------------------------------------------------------------------
3rdparty/stout/include/stout/protobuf.hpp | 201 ++++++++++++++++---------
1 file changed, 134 insertions(+), 67 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/mesos/blob/5b226140/3rdparty/stout/include/stout/protobuf.hpp
----------------------------------------------------------------------
diff --git a/3rdparty/stout/include/stout/protobuf.hpp b/3rdparty/stout/include/stout/protobuf.hpp
index 69a54c9..2fa5072 100644
--- a/3rdparty/stout/include/stout/protobuf.hpp
+++ b/3rdparty/stout/include/stout/protobuf.hpp
@@ -382,12 +382,51 @@ struct Parser : boost::static_visitor<Try<Nothing>>
{
switch (field->type()) {
case google::protobuf::FieldDescriptor::TYPE_MESSAGE:
- // TODO(gilbert): We currently push up the nested error
- // messages without wrapping the error message (due to
- // the recursive nature of parse). We should pass along
- // variable information in order to construct a helpful
- // error message, e.g. "Failed to parse field 'a.b.c': ...".
- if (field->is_repeated()) {
+ if (field->is_map()) {
+ foreachpair (
+ const std::string& name,
+ const JSON::Value& value,
+ object.values) {
+ google::protobuf::Message* entry =
+ reflection->AddMessage(message, field);
+
+ // A map is equivalent to:
+ //
+ // message MapFieldEntry {
+ // optional key_type key = 1;
+ // optional value_type value = 2;
+ // }
+ //
+ // repeated MapFieldEntry map_field = N;
+ //
+ // See the link below for details:
+ // https://developers.google.com/protocol-buffers/docs/proto#maps
+ const google::protobuf::FieldDescriptor* key_field =
+ entry->GetDescriptor()->FindFieldByNumber(1);
+
+ JSON::Value key(name);
+
+ Try<Nothing> apply =
+ boost::apply_visitor(Parser(entry, key_field), key);
+
+ if (apply.isError()) {
+ return Error(apply.error());
+ }
+
+ const google::protobuf::FieldDescriptor* value_field =
+ entry->GetDescriptor()->FindFieldByNumber(2);
+
+ apply = boost::apply_visitor(Parser(entry, value_field), value);
+ if (apply.isError()) {
+ return Error(apply.error());
+ }
+ }
+ } else if (field->is_repeated()) {
+ // TODO(gilbert): We currently push up the nested error
+ // messages without wrapping the error message (due to
+ // the recursive nature of parse). We should pass along
+ // variable information in order to construct a helpful
+ // error message, e.g. "Failed to parse field 'a.b.c': ...".
return parse(reflection->AddMessage(message, field), object);
} else {
return parse(reflection->MutableMessage(message, field), object);
@@ -864,6 +903,56 @@ inline Object protobuf(const google::protobuf::Message& message)
const google::protobuf::Descriptor* descriptor = message.GetDescriptor();
const google::protobuf::Reflection* reflection = message.GetReflection();
+ auto value_for_field = [](
+ const google::protobuf::Message& message,
+ const google::protobuf::FieldDescriptor* field) -> JSON::Value {
+ const google::protobuf::Reflection* reflection = message.GetReflection();
+
+ switch (field->type()) {
+ case google::protobuf::FieldDescriptor::TYPE_DOUBLE:
+ return JSON::Number(reflection->GetDouble(message, field));
+ case google::protobuf::FieldDescriptor::TYPE_FLOAT:
+ return JSON::Number(reflection->GetFloat(message, field));
+ case google::protobuf::FieldDescriptor::TYPE_INT64:
+ case google::protobuf::FieldDescriptor::TYPE_SINT64:
+ case google::protobuf::FieldDescriptor::TYPE_SFIXED64:
+ return JSON::Number(reflection->GetInt64(message, field));
+ case google::protobuf::FieldDescriptor::TYPE_UINT64:
+ case google::protobuf::FieldDescriptor::TYPE_FIXED64:
+ return JSON::Number(reflection->GetUInt64(message, field));
+ case google::protobuf::FieldDescriptor::TYPE_INT32:
+ case google::protobuf::FieldDescriptor::TYPE_SINT32:
+ case google::protobuf::FieldDescriptor::TYPE_SFIXED32:
+ return JSON::Number(reflection->GetInt32(message, field));
+ case google::protobuf::FieldDescriptor::TYPE_UINT32:
+ case google::protobuf::FieldDescriptor::TYPE_FIXED32:
+ return JSON::Number(reflection->GetUInt32(message, field));
+ case google::protobuf::FieldDescriptor::TYPE_BOOL:
+ if (reflection->GetBool(message, field)) {
+ return JSON::Boolean(true);
+ } else {
+ return JSON::Boolean(false);
+ }
+ break;
+ case google::protobuf::FieldDescriptor::TYPE_STRING:
+ return JSON::String(reflection->GetString(message, field));
+ case google::protobuf::FieldDescriptor::TYPE_BYTES:
+ return JSON::String(
+ base64::encode(reflection->GetString(message, field)));
+ case google::protobuf::FieldDescriptor::TYPE_MESSAGE:
+ return protobuf(reflection->GetMessage(message, field));
+ case google::protobuf::FieldDescriptor::TYPE_ENUM:
+ return JSON::String(reflection->GetEnum(message, field)->name());
+ case google::protobuf::FieldDescriptor::TYPE_GROUP:
+ // Deprecated! We abort here instead of using a Try as return value,
+ // because we expect this code path to never be taken.
+ ABORT("Unhandled protobuf field type: " +
+ stringify(field->type()));
+ }
+
+ UNREACHABLE();
+ };
+
// We first look through all the possible fields to determine both
// the set fields _and_ the optional fields with a default that
// are not set. Reflection::ListFields() alone will only include
@@ -886,7 +975,44 @@ inline Object protobuf(const google::protobuf::Message& message)
}
foreach (const google::protobuf::FieldDescriptor* field, fields) {
- if (field->is_repeated()) {
+ if (field->is_map()) {
+ JSON::Object map;
+
+ int fieldSize = reflection->FieldSize(message, field);
+ for (int i = 0; i < fieldSize; ++i) {
+ const google::protobuf::Message& entry =
+ reflection->GetRepeatedMessage(message, field, i);
+
+ // A map is equivalent to:
+ //
+ // message MapFieldEntry {
+ // optional key_type key = 1;
+ // optional value_type value = 2;
+ // }
+ //
+ // repeated MapFieldEntry map_field = N;
+ //
+ // See the link below for details:
+ // https://developers.google.com/protocol-buffers/docs/proto#maps
+ const google::protobuf::FieldDescriptor* key_field =
+ entry.GetDescriptor()->FindFieldByNumber(1);
+
+ const google::protobuf::FieldDescriptor* value_field =
+ entry.GetDescriptor()->FindFieldByNumber(2);
+
+ JSON::Value key = value_for_field(entry, key_field);
+
+ std::string name;
+ if (key.is<JSON::String>()) {
+ name = key.as<JSON::String>().value;
+ } else {
+ name = jsonify(key);
+ }
+
+ map.values[name] = value_for_field(entry, value_field);
+ }
+ object.values[field->name()] = map;
+ } else if (field->is_repeated()) {
JSON::Array array;
int fieldSize = reflection->FieldSize(message, field);
array.values.reserve(fieldSize);
@@ -954,66 +1080,7 @@ inline Object protobuf(const google::protobuf::Message& message)
}
object.values[field->name()] = array;
} else {
- switch (field->type()) {
- case google::protobuf::FieldDescriptor::TYPE_DOUBLE:
- object.values[field->name()] =
- JSON::Number(reflection->GetDouble(message, field));
- break;
- case google::protobuf::FieldDescriptor::TYPE_FLOAT:
- object.values[field->name()] =
- JSON::Number(reflection->GetFloat(message, field));
- break;
- case google::protobuf::FieldDescriptor::TYPE_INT64:
- case google::protobuf::FieldDescriptor::TYPE_SINT64:
- case google::protobuf::FieldDescriptor::TYPE_SFIXED64:
- object.values[field->name()] =
- JSON::Number(reflection->GetInt64(message, field));
- break;
- case google::protobuf::FieldDescriptor::TYPE_UINT64:
- case google::protobuf::FieldDescriptor::TYPE_FIXED64:
- object.values[field->name()] =
- JSON::Number(reflection->GetUInt64(message, field));
- break;
- case google::protobuf::FieldDescriptor::TYPE_INT32:
- case google::protobuf::FieldDescriptor::TYPE_SINT32:
- case google::protobuf::FieldDescriptor::TYPE_SFIXED32:
- object.values[field->name()] =
- JSON::Number(reflection->GetInt32(message, field));
- break;
- case google::protobuf::FieldDescriptor::TYPE_UINT32:
- case google::protobuf::FieldDescriptor::TYPE_FIXED32:
- object.values[field->name()] =
- JSON::Number(reflection->GetUInt32(message, field));
- break;
- case google::protobuf::FieldDescriptor::TYPE_BOOL:
- if (reflection->GetBool(message, field)) {
- object.values[field->name()] = JSON::Boolean(true);
- } else {
- object.values[field->name()] = JSON::Boolean(false);
- }
- break;
- case google::protobuf::FieldDescriptor::TYPE_STRING:
- object.values[field->name()] =
- JSON::String(reflection->GetString(message, field));
- break;
- case google::protobuf::FieldDescriptor::TYPE_BYTES:
- object.values[field->name()] = JSON::String(
- base64::encode(reflection->GetString(message, field)));
- break;
- case google::protobuf::FieldDescriptor::TYPE_MESSAGE:
- object.values[field->name()] =
- protobuf(reflection->GetMessage(message, field));
- break;
- case google::protobuf::FieldDescriptor::TYPE_ENUM:
- object.values[field->name()] =
- JSON::String(reflection->GetEnum(message, field)->name());
- break;
- case google::protobuf::FieldDescriptor::TYPE_GROUP:
- // Deprecated! We abort here instead of using a Try as return value,
- // because we expect this code path to never be taken.
- ABORT("Unhandled protobuf field type: " +
- stringify(field->type()));
- }
+ object.values[field->name()] = value_for_field(message, field);
}
}