in src/mcpack2pb/generator.cpp [857:1281]
static bool generate_serializing(const google::protobuf::Descriptor* d,
std::set<std::string> & ref_msgs,
std::set<std::string> & ref_maps,
google::protobuf::io::Printer & impl) {
std::string var_name = mcpack2pb::to_var_name(d->full_name());
std::string cpp_name = mcpack2pb::to_cpp_name(d->full_name());
ref_msgs.insert(var_name);
impl.Print(
"void serialize_$vmsg$_body(\n"
" const ::google::protobuf::Message& msg_base,\n"
" ::mcpack2pb::Serializer& serializer,\n"
" ::mcpack2pb::SerializationFormat format) {\n"
" (void)format; // suppress compiler warning when it's not used\n"
, "vmsg", var_name);
if (d->field_count()) {
impl.Print(
" const $msg$& msg = static_cast<const $msg$&>(msg_base);\n"
, "msg", cpp_name);
} else {
impl.Print(" (void)msg_base; // ^\n"
" (void)serializer; // ^\n");
}
impl.Indent();
for (int i = 0; i < d->field_count(); ++i) {
const google::protobuf::FieldDescriptor* f = d->field(i);
ConvertibleIdlType cit = f->options().GetExtension(idl_type);
// Print the field as comment.
std::string comment_template;
if (cit == IDL_AUTO) {
butil::string_printf(&comment_template,
"// %s $type$ $name$ = $number$;\n",
(f->is_repeated() ? "repeated" :
(f->is_optional() ? "optional" : "required")));
} else {
butil::string_printf(&comment_template,
"// %s $type$ $name$ = $number$ [(idl_type)=%s];\n",
(f->is_repeated() ? "repeated" :
(f->is_optional() ? "optional" : "required")),
describe_idl_type(cit));
}
impl.Print(comment_template.c_str()
, "type", field_to_string(f)
, "name", f->name()
, "number", butil::string_printf("%d", f->number()));
if (f->is_repeated()) {
switch (f->cpp_type()) {
case google::protobuf::FieldDescriptor::CPPTYPE_INT32:
case google::protobuf::FieldDescriptor::CPPTYPE_UINT32:
case google::protobuf::FieldDescriptor::CPPTYPE_ENUM:
TEMPLATE_SERIALIZE_REPEATED_INTEGRAL(
cit, impl, f, (cit == IDL_INT32 || cit == IDL_UINT32));
break;
case google::protobuf::FieldDescriptor::CPPTYPE_INT64:
case google::protobuf::FieldDescriptor::CPPTYPE_UINT64:
TEMPLATE_SERIALIZE_REPEATED_INTEGRAL(
cit, impl, f, (cit == IDL_INT64 || cit == IDL_UINT64));
break;
case google::protobuf::FieldDescriptor::CPPTYPE_BOOL:
TEMPLATE_SERIALIZE_REPEATED(
cit, impl, f, (cit == IDL_AUTO || cit == IDL_BOOL), false);
break;
case google::protobuf::FieldDescriptor::CPPTYPE_FLOAT:
TEMPLATE_SERIALIZE_REPEATED(
cit, impl, f,
(cit == IDL_AUTO || cit == IDL_FLOAT), (cit == IDL_DOUBLE));
break;
case google::protobuf::FieldDescriptor::CPPTYPE_DOUBLE:
TEMPLATE_SERIALIZE_REPEATED(
cit, impl, f,
(cit == IDL_AUTO || cit == IDL_DOUBLE), (cit == IDL_FLOAT));
break;
case google::protobuf::FieldDescriptor::CPPTYPE_STRING:
if (f->type() == google::protobuf::FieldDescriptor::TYPE_STRING) {
TEMPLATE_SERIALIZE_REPEATED(
cit, impl, f, false, (cit == IDL_AUTO || cit == IDL_STRING));
} else if (f->type() == google::protobuf::FieldDescriptor::TYPE_BYTES) {
TEMPLATE_SERIALIZE_REPEATED(
cit, impl, f, false,
(cit == IDL_AUTO || cit == IDL_BINARY || cit == IDL_STRING));
} else {
LOG(ERROR) << "Unknown pb type=" << f->type();
return false;
}
break;
case google::protobuf::FieldDescriptor::CPPTYPE_MESSAGE: {
if (cit != IDL_AUTO) {
LOG(ERROR) << "Disallow converting " << f->full_name()
<< " (" << f->message_type()->full_name() << ") to "
<< to_mcpack_typestr(cit, f) << " (idl)";
return false;
}
const google::protobuf::Descriptor* msg2 = f->message_type();
std::string var_name2 = mcpack2pb::to_var_name(msg2->full_name());
std::string cpp_name2 = mcpack2pb::to_cpp_name(msg2->full_name());
if (is_map_entry(msg2)) {
ref_maps.insert(var_name2);
impl.Print(
"serializer.begin_object(\"$field$\");\n"
"for (int i = 0; i < msg.$lcfield$_size(); ++i) {\n"
" const $msg2$& pair = msg.$lcfield$(i);\n"
, "field", get_idl_name(f)
, "lcfield", f->lowercase_name()
, "msg2", cpp_name2);
const google::protobuf::FieldDescriptor* value_desc = msg2->field(1);
switch (value_desc->cpp_type()) {
case google::protobuf::FieldDescriptor::CPPTYPE_INT32:
impl.Print(" serializer.add_int32(pair.key(), pair.value());\n");
break;
case google::protobuf::FieldDescriptor::CPPTYPE_UINT32:
impl.Print(" serializer.add_uint32(pair.key(), pair.value());\n");
break;
case google::protobuf::FieldDescriptor::CPPTYPE_ENUM:
impl.Print(" serializer.add_int32(pair.key(), (int32_t)pair.value());\n");
break;
case google::protobuf::FieldDescriptor::CPPTYPE_INT64:
impl.Print(" serializer.add_int64(pair.key(), pair.value());\n");
break;
case google::protobuf::FieldDescriptor::CPPTYPE_UINT64:
impl.Print(" serializer.add_uint64(pair.key(), pair.value());\n");
break;
case google::protobuf::FieldDescriptor::CPPTYPE_BOOL:
impl.Print(" serializer.add_bool(pair.key(), pair.value());\n");
break;
case google::protobuf::FieldDescriptor::CPPTYPE_FLOAT:
impl.Print(" serializer.add_float(pair.key(), pair.value());\n");
break;
case google::protobuf::FieldDescriptor::CPPTYPE_DOUBLE:
impl.Print(" serializer.add_double(pair.key(), pair.value());\n");
break;
case google::protobuf::FieldDescriptor::CPPTYPE_STRING:
impl.Print(" serializer.add_string(pair.key(), pair.value());\n");
break;
case google::protobuf::FieldDescriptor::CPPTYPE_MESSAGE: {
std::string var_name3 = mcpack2pb::to_var_name(
value_desc->message_type()->full_name());
ref_msgs.insert(var_name3);
impl.Print(
" serializer.begin_object(pair.key());\n"
" serialize_$vmsg3$_body(pair.value(), serializer, format);\n"
" serializer.end_object();\n"
, "vmsg3", var_name3);
} break;
} // switch
impl.Print(
"}\n"
"serializer.end_object();\n");
break;
}
ref_msgs.insert(var_name2);
impl.Print(
"if (format == ::mcpack2pb::FORMAT_MCPACK_V2) {\n"
" if (msg.$lcfield$_size()) {\n"
" serializer.begin_mcpack_array(\"$field$\", ::mcpack2pb::FIELD_OBJECT);\n"
" for (int i = 0; i < msg.$lcfield$_size(); ++i) {\n"
" serializer.begin_object();\n"
" serialize_$vmsg2$_body(msg.$lcfield$(i), serializer, format);\n"
" serializer.end_object();\n"
" }\n"
" serializer.end_array();\n"
" }"
, "field", get_idl_name(f)
, "lcfield", f->lowercase_name()
, "vmsg2", var_name2);
if (f->options().GetExtension(idl_on)) {
impl.Print(
" else {\n"
" serializer.add_empty_array(\"$field$\");\n"
" }\n", "field", get_idl_name(f));
} else {
impl.Print("\n");
}
impl.Print("} else if (msg.$lcfield$_size()) {\n"
, "lcfield", f->lowercase_name());
impl.Indent();
impl.Print("serializer.begin_object(\"$field$\");\n"
, "field", get_idl_name(f));
for (int j = 0; j < msg2->field_count(); ++j) {
const google::protobuf::FieldDescriptor* f2 = msg2->field(j);
ConvertibleIdlType cit2 = f2->options().GetExtension(idl_type);
impl.Print(
"serializer.begin_mcpack_array(\"$f2$\", ::mcpack2pb::FIELD_$TYPE$);\n"
"for (int i = 0; i < msg.$lcfield$_size(); ++i) {\n"
, "f2", get_idl_name(f2)
, "TYPE", (f2->is_repeated() ? "ARRAY" : to_mcpack_typestr_uppercase(cit2, (f2)))
, "lcfield", f->lowercase_name());
impl.Indent();
if (f2->cpp_type() == google::protobuf::FieldDescriptor::CPPTYPE_MESSAGE) {
if (cit2 != IDL_AUTO) {
LOG(ERROR) << "Disallow converting " << f2->full_name()
<< " (" << f2->message_type()->full_name() << ") to "
<< to_mcpack_typestr(cit2, f2) << " (idl)";
return false;
}
std::string var_name3 = mcpack2pb::to_var_name(f2->message_type()->full_name());
ref_msgs.insert(var_name3);
if (f2->is_repeated()) {
impl.Print(
"const int $lcfield2$_size = msg.$lcfield$(i).$lcfield2$_size();\n"
"if ($lcfield2$_size) {\n"
" serializer.begin_mcpack_array(::mcpack2pb::FIELD_OBJECT);\n"
" for (int j = 0; j < $lcfield2$_size; ++j) {\n"
" serializer.begin_object();\n"
" serialize_$vmsg3$_body(msg.$lcfield$(i).$lcfield2$(j), serializer, format);\n"
" serializer.end_object();\n"
" }\n"
" serializer.end_array();\n"
"}"
, "vmsg3", var_name3
, "lcfield", f->lowercase_name()
, "lcfield2", f2->lowercase_name());
if (f2->options().GetExtension(idl_on)) {
impl.Print(
" else {\n"
" serializer.add_empty_array();\n"
"}\n");
} else {
impl.Print(
" else {\n"
" serializer.add_null();\n"
"}\n");
}
} else {
impl.Print(
"if (msg.$lcfield$(i).has_$lcfield2$()) {\n"
" serializer.begin_object();\n"
" serialize_$vmsg3$_body(msg.$lcfield$(i).$lcfield2$(), serializer, format);\n"
" serializer.end_object();\n"
"} else {\n"
" serializer.add_null();\n"
"}\n"
, "vmsg3", var_name3
, "lcfield", f->lowercase_name()
, "lcfield2", f2->lowercase_name());
}
} else if (f2->is_repeated()) {
const std::string msgstr = butil::string_printf(
"msg.%s(i)", f->lowercase_name().c_str());
switch (f2->cpp_type()) {
case google::protobuf::FieldDescriptor::CPPTYPE_INT32:
case google::protobuf::FieldDescriptor::CPPTYPE_UINT32:
case google::protobuf::FieldDescriptor::CPPTYPE_ENUM:
TEMPLATE_INNER_SERIALIZE_REPEATED_INTEGRAL(
msgstr.c_str(), cit2, impl, f2,
(cit2 == IDL_INT32 || cit2 == IDL_UINT32));
break;
case google::protobuf::FieldDescriptor::CPPTYPE_INT64:
case google::protobuf::FieldDescriptor::CPPTYPE_UINT64:
TEMPLATE_INNER_SERIALIZE_REPEATED_INTEGRAL(
msgstr.c_str(), cit2, impl, f2,
(cit2 == IDL_INT64 || cit2 == IDL_UINT64));
break;
case google::protobuf::FieldDescriptor::CPPTYPE_BOOL:
TEMPLATE_INNER_SERIALIZE_REPEATED(
msgstr.c_str(), cit2, impl, f2,
(cit2 == IDL_AUTO || cit2 == IDL_BOOL), false);
break;
case google::protobuf::FieldDescriptor::CPPTYPE_FLOAT:
TEMPLATE_INNER_SERIALIZE_REPEATED(
msgstr.c_str(), cit2, impl, f2,
(cit2 == IDL_AUTO || cit2 == IDL_FLOAT), (cit2 == IDL_DOUBLE));
break;
case google::protobuf::FieldDescriptor::CPPTYPE_DOUBLE:
TEMPLATE_INNER_SERIALIZE_REPEATED(
msgstr.c_str(), cit2, impl, f2,
(cit2 == IDL_AUTO || cit2 == IDL_DOUBLE), (cit2 == IDL_FLOAT));
break;
case google::protobuf::FieldDescriptor::CPPTYPE_STRING:
if (f2->type() == google::protobuf::FieldDescriptor::TYPE_STRING) {
TEMPLATE_INNER_SERIALIZE_REPEATED(
msgstr.c_str(), cit2, impl, f2, false,
(cit2 == IDL_AUTO || cit2 == IDL_STRING));
} else if (f2->type() == google::protobuf::FieldDescriptor::TYPE_BYTES) {
TEMPLATE_INNER_SERIALIZE_REPEATED(
msgstr.c_str(), cit2, impl, f2, false,
(cit2 == IDL_AUTO || cit2 == IDL_BINARY || cit2 == IDL_STRING));
} else {
LOG(ERROR) << "Unknown pb type=" << f2->type();
return false;
}
break;
case google::protobuf::FieldDescriptor::CPPTYPE_MESSAGE:
CHECK(false) << "Impossible";
return false;
}
} else {
const std::string msgstr = butil::string_printf(
"msg.%s(i)", f->lowercase_name().c_str());
switch (f2->cpp_type()) {
case google::protobuf::FieldDescriptor::CPPTYPE_INT32:
case google::protobuf::FieldDescriptor::CPPTYPE_INT64:
case google::protobuf::FieldDescriptor::CPPTYPE_UINT32:
case google::protobuf::FieldDescriptor::CPPTYPE_UINT64:
case google::protobuf::FieldDescriptor::CPPTYPE_ENUM:
TEMPLATE_INNER_SERIALIZE_INTEGRAL(msgstr.c_str(), cit2, impl, f2);
break;
case google::protobuf::FieldDescriptor::CPPTYPE_BOOL:
TEMPLATE_INNER_SERIALIZE(
msgstr.c_str(), cit2, impl, f2,
(cit2 == IDL_AUTO || cit2 == IDL_BOOL));
break;
case google::protobuf::FieldDescriptor::CPPTYPE_FLOAT:
TEMPLATE_INNER_SERIALIZE(
msgstr.c_str(), cit2, impl, f2,
(cit2 == IDL_AUTO || cit2 == IDL_FLOAT));
break;
case google::protobuf::FieldDescriptor::CPPTYPE_DOUBLE:
TEMPLATE_INNER_SERIALIZE(
msgstr.c_str(), cit2, impl, f2,
(cit2 == IDL_AUTO || cit2 == IDL_FLOAT || cit2 == IDL_DOUBLE));
break;
case google::protobuf::FieldDescriptor::CPPTYPE_STRING:
if (f2->type() == google::protobuf::FieldDescriptor::TYPE_STRING) {
TEMPLATE_INNER_SERIALIZE(
msgstr.c_str(), cit2, impl, f2,
(cit2 == IDL_AUTO || cit2 == IDL_STRING));
} else if (f2->type() == google::protobuf::FieldDescriptor::TYPE_BYTES) {
TEMPLATE_INNER_SERIALIZE(
msgstr.c_str(), cit2, impl, f2,
(cit2 == IDL_AUTO || cit2 == IDL_BINARY || cit2 == IDL_STRING));
} else {
LOG(ERROR) << "Unknown pb type=" << f2->type();
return false;
}
break;
case google::protobuf::FieldDescriptor::CPPTYPE_MESSAGE:
LOG(ERROR) << "Impossible";
return false;
}
}
impl.Outdent();
impl.Print("}\n"
"serializer.end_array();\n");
}
impl.Print("serializer.end_object_iso();\n");
impl.Outdent();
impl.Print("} else {\n"
" serializer.begin_object(\"$field$\");\n"
" serializer.end_object_iso();\n"
"}\n"
, "field", get_idl_name(f));
} break;
} // switch
} else {
switch (f->cpp_type()) {
case google::protobuf::FieldDescriptor::CPPTYPE_INT32:
case google::protobuf::FieldDescriptor::CPPTYPE_INT64:
case google::protobuf::FieldDescriptor::CPPTYPE_UINT32:
case google::protobuf::FieldDescriptor::CPPTYPE_UINT64:
case google::protobuf::FieldDescriptor::CPPTYPE_ENUM:
TEMPLATE_SERIALIZE_INTEGRAL(cit, impl, f);
break;
case google::protobuf::FieldDescriptor::CPPTYPE_BOOL:
TEMPLATE_SERIALIZE(cit, impl, f,
(cit == IDL_AUTO || cit == IDL_BOOL));
break;
case google::protobuf::FieldDescriptor::CPPTYPE_FLOAT:
TEMPLATE_SERIALIZE(cit, impl, f,
(cit == IDL_AUTO || cit == IDL_FLOAT));
break;
case google::protobuf::FieldDescriptor::CPPTYPE_DOUBLE:
TEMPLATE_SERIALIZE(
cit, impl, f,
(cit == IDL_AUTO || cit == IDL_FLOAT || cit == IDL_DOUBLE));
break;
case google::protobuf::FieldDescriptor::CPPTYPE_STRING:
if (f->type() == google::protobuf::FieldDescriptor::TYPE_STRING) {
TEMPLATE_SERIALIZE(
cit, impl, f, (cit == IDL_AUTO || cit == IDL_STRING));
} else if (f->type() == google::protobuf::FieldDescriptor::TYPE_BYTES) {
TEMPLATE_SERIALIZE(
cit, impl, f,
(cit == IDL_AUTO || cit == IDL_BINARY || cit == IDL_STRING));
} else {
LOG(ERROR) << "Unknown pb type=" << f->type();
return false;
}
break;
case google::protobuf::FieldDescriptor::CPPTYPE_MESSAGE: {
if (cit != IDL_AUTO) {
LOG(ERROR) << "Disallow converting " << f->full_name()
<< " (" << f->message_type()->full_name() << ") to "
<< to_mcpack_typestr(cit, f) << " (idl)";
return false;
}
std::string var_name2 = mcpack2pb::to_var_name(f->message_type()->full_name());
ref_msgs.insert(var_name2);
impl.Print("if (msg.has_$lcfield$()) {\n"
" serializer.begin_object(\"$field$\");\n"
" serialize_$vmsg$_body(msg.$lcfield$(), serializer, format);\n"
" serializer.end_object();\n"
"}"
, "field", get_idl_name(f)
, "lcfield", f->lowercase_name()
, "vmsg", var_name2);
} break;
} // switch
if (f->is_required()) {
impl.Print(" else {\n"
" LOG(ERROR) << \"Missing required $field$\";\n"
" return serializer.set_bad();\n"
"}\n", "field", f->full_name());
} else {
impl.Print("\n");
}
} // else
}
impl.Outdent();
impl.Print(
"}\n"
"bool serialize_$vmsg$(\n"
" const ::google::protobuf::Message& msg_base,\n"
" ::google::protobuf::io::ZeroCopyOutputStream* output,\n"
" ::mcpack2pb::SerializationFormat format) {\n"
" ::mcpack2pb::OutputStream ostream(output);\n"
" ::mcpack2pb::Serializer serializer(&ostream);\n"
" serializer.begin_object();\n"
" serialize_$vmsg$_body(msg_base, serializer, format);\n"
" serializer.end_object();\n"
" ostream.done();\n"
" return serializer.good();\n"
"}\n"
, "vmsg", var_name);
return !impl.failed();
}