in src/mcpack2pb/generator.cpp [268:649]
static bool generate_parsing(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("\n// $msg$ from mcpack\n", "msg", d->full_name());
for (int i = 0; i < d->field_count(); ++i) {
const google::protobuf::FieldDescriptor* f = d->field(i);
if (f->is_repeated()) {
impl.Print("// repeated $type$ $name$ = $number$;\n"
, "type", field_to_string(f)
, "name", f->name()
, "number", butil::string_printf("%d", f->number()));
impl.Print(TEMPLATE_OF_ADD_FUNC_SIGNATURE()
, "vmsg", var_name
, "lcfield", f->lowercase_name());
switch (f->cpp_type()) {
case google::protobuf::FieldDescriptor::CPPTYPE_INT32:
impl.Print(TEMPLATE_OF_ADD_FUNC_BODY(int32, int32)
, "msg", cpp_name
, "field", f->full_name()
, "lcfield", f->lowercase_name());
break;
case google::protobuf::FieldDescriptor::CPPTYPE_INT64:
impl.Print(TEMPLATE_OF_ADD_FUNC_BODY(int64, int64)
, "msg", cpp_name
, "field", f->full_name()
, "lcfield", f->lowercase_name());
break;
case google::protobuf::FieldDescriptor::CPPTYPE_UINT32:
impl.Print(TEMPLATE_OF_ADD_FUNC_BODY(uint32, uint32)
, "msg", cpp_name
, "field", f->full_name()
, "lcfield", f->lowercase_name());
break;
case google::protobuf::FieldDescriptor::CPPTYPE_UINT64:
impl.Print(TEMPLATE_OF_ADD_FUNC_BODY(uint64, uint64)
, "msg", cpp_name
, "field", f->full_name()
, "lcfield", f->lowercase_name());
break;
case google::protobuf::FieldDescriptor::CPPTYPE_BOOL:
impl.Print(TEMPLATE_OF_ADD_FUNC_BODY(bool, bool)
, "msg", cpp_name
, "field", f->full_name()
, "lcfield", f->lowercase_name());
break;
case google::protobuf::FieldDescriptor::CPPTYPE_ENUM:
impl.Print(
"{\n"
" $msg$* const msg = static_cast<$msg$*>(msg_base);\n"
" if (value.type() == ::mcpack2pb::FIELD_ISOARRAY) {\n"
" ::mcpack2pb::ISOArrayIterator it(value);\n"
" msg->mutable_$lcfield$()->Reserve(it.item_count());\n"
" for (; it != NULL; ++it) {\n"
" msg->add_$lcfield$(($enum$)it.as_int32());\n"
" }\n"
" return value.stream()->good();\n"
" } else if (value.type() == ::mcpack2pb::FIELD_ARRAY) {\n"
" ::mcpack2pb::ArrayIterator it(value);\n"
" msg->mutable_$lcfield$()->Reserve(it.item_count());\n"
" for (; it != NULL; ++it) {\n"
" msg->add_$lcfield$(($enum$)it->as_int32(\"$enum$\"));\n"
" }\n"
" return value.stream()->good();\n"
" }\n"
" LOG(ERROR) << \"Can't set \" << value << \" to repeated $enum$\";\n"
" return false;\n"
"}\n"
, "msg", cpp_name
, "enum", to_cpp_name(f->enum_type()->full_name())
, "lcfield", f->lowercase_name());
break;
case google::protobuf::FieldDescriptor::CPPTYPE_FLOAT:
impl.Print(TEMPLATE_OF_ADD_FUNC_BODY(float, float)
, "msg", cpp_name
, "field", f->full_name()
, "lcfield", f->lowercase_name());
break;
case google::protobuf::FieldDescriptor::CPPTYPE_DOUBLE:
impl.Print(TEMPLATE_OF_ADD_FUNC_BODY(double, double)
, "msg", cpp_name
, "field", f->full_name()
, "lcfield", f->lowercase_name());
break;
case google::protobuf::FieldDescriptor::CPPTYPE_STRING:
impl.Print(
"{\n"
" $msg$* const msg = static_cast<$msg$*>(msg_base);\n"
" if (value.type() == ::mcpack2pb::FIELD_ARRAY) {\n"
" ::mcpack2pb::ArrayIterator it(value);\n"
" msg->mutable_$lcfield$()->Reserve(it.item_count());\n"
" for (; it != NULL; ++it) {\n"
" if (it->type() == ::mcpack2pb::FIELD_STRING) {\n"
" it->as_string(msg->add_$lcfield$(), \"$field$\");\n"
" } else if (it->type() == ::mcpack2pb::FIELD_BINARY) {\n"
" it->as_binary(msg->add_$lcfield$(), \"$field$\");\n"
" } else {\n"
" LOG(ERROR) << \"Can't add \" << *it << \" to $field$ (repeated string)\";\n"
" return false;\n"
" }\n"
" }\n"
" return value.stream()->good();\n"
" }\n"
" LOG(ERROR) << \"Can't set \" << value << \" to $field$ (repeated string)\";\n"
" return false;\n"
"}\n"
, "msg", cpp_name
, "field", f->full_name()
, "lcfield", f->lowercase_name());
break;
case google::protobuf::FieldDescriptor::CPPTYPE_MESSAGE: {
std::string var_name2 = mcpack2pb::to_var_name(f->message_type()->full_name());
std::string cpp_name2 = mcpack2pb::to_cpp_name(f->message_type()->full_name());
if (is_map_entry(f->message_type())) {
ref_maps.insert(var_name2);
impl.Print(
"{\n"
" $msg$* const msg = static_cast<$msg$*>(msg_base);\n"
" if (value.type() == ::mcpack2pb::FIELD_OBJECT) {\n"
" ::mcpack2pb::ObjectIterator it(value);\n"
" for (; it != NULL; ++it) {\n"
" $msg2$* sub = msg->add_$lcfield$();\n"
" sub->set_key(it->name.data(), it->name.size());\n"
, "msg", cpp_name
, "msg2", cpp_name2
, "lcfield", f->lowercase_name());
impl.Print(
" if (!set_$vmsg2$_value(sub, it->value)) {\n"
" return false;\n"
" }\n"
" }\n"
" return value.stream()->good();\n"
" }\n"
" LOG(ERROR) << \"Can't set \" << value << \" to $field$ (repeated $msg2$)\";\n"
" return false;\n"
"}\n"
, "vmsg2", var_name2
, "msg2", f->message_type()->full_name()
, "field", f->full_name());
break;
}
ref_msgs.insert(var_name2);
impl.Print(
"{\n"
" $msg$* const msg = static_cast<$msg$*>(msg_base);\n"
" if (value.type() == ::mcpack2pb::FIELD_OBJECTISOARRAY) {\n"
" ::mcpack2pb::ObjectIterator it(value);\n"
" for (; it != NULL; ++it) {\n"
" ::mcpack2pb::SetFieldFn* fn = g_$vmsg2$_fields->seek(it->name);\n"
" if (!fn) {\n"
" if (!FLAGS_mcpack2pb_absent_field_is_error) {\n"
" continue;\n"
" } else {\n"
" LOG(ERROR) << \"No field=\" << it->name << \" (\"\n"
" << value << \") in $msg$\";\n"
" return false;\n"
" }\n"
" }\n"
" if (it->value.type() == ::mcpack2pb::FIELD_ARRAY) {\n"
" ::mcpack2pb::ArrayIterator it2(it->value);\n"
" int i = 0;\n"
" for (; it2 != NULL; ++it2, ++i) {\n"
" ::google::protobuf::Message* sub_msg = NULL;\n"
" if (i < msg->$lcfield$_size()) {\n"
" sub_msg = msg->mutable_$lcfield$(i);\n"
" } else {\n"
" sub_msg = msg->add_$lcfield$();\n"
" }\n"
" if (it2->type() != ::mcpack2pb::FIELD_NULL) {\n"
" if (!(*fn)(sub_msg, *it2)) {\n"
" LOG(ERROR) << \"Fail to set item of \" << it->name;\n"
" return false;\n"
" }\n"
" }\n"
" }\n"
" } else if (it->value.type() == ::mcpack2pb::FIELD_ISOARRAY) {\n"
" LOG(ERROR) << \"Shouldn't be a iso array, name=\" << it->name;\n"
" return false;\n"
" } else {\n"
" LOG(ERROR) << \"Can't add \" << value << \" to repeated $msg$\";\n"
" return false;\n"
" }\n"
" }\n"
" return value.stream()->good();\n"
" } else if (value.type() == ::mcpack2pb::FIELD_ARRAY) {\n"
" ::mcpack2pb::ArrayIterator it(value);\n"
" msg->mutable_$lcfield$()->Reserve(it.item_count());\n"
" for (; it != NULL; ++it) {\n"
" if (it->type() == ::mcpack2pb::FIELD_OBJECT) {\n"
" if (!parse_$vmsg2$_body_internal(msg->add_$lcfield$(), *it)) {\n"
" return false;\n"
" }\n"
" } else {\n"
" LOG(ERROR) << \"Can't add \" << *it << \" to repeated $msg$\";\n"
" return false;\n"
" }\n"
" }\n"
" return value.stream()->good();\n"
" }\n"
, "vmsg2", var_name2
, "msg", cpp_name
, "lcfield", f->lowercase_name());
impl.Print(
" LOG(ERROR) << \"Can't set \" << value << \" to $field$ (repeated $msg2$)\";\n"
" return false;\n"
"}\n"
, "msg2", f->message_type()->full_name()
, "field", f->full_name());
} break;
} // switch
} else {
if (f->is_optional()) {
impl.Print("// optional $type$ $name$ = $number$;\n"
, "type", field_to_string(f)
, "name", f->name()
, "number", butil::string_printf("%d", f->number()));
} else {
impl.Print("// required $type$ $name$ = $number$;\n"
, "type", field_to_string(f)
, "name", f->name()
, "number", butil::string_printf("%d", f->number()));
}
impl.Print(TEMPLATE_OF_SET_FUNC_SIGNATURE()
, "vmsg", var_name
, "lcfield", f->lowercase_name());
switch (f->cpp_type()) {
case google::protobuf::FieldDescriptor::CPPTYPE_INT32:
impl.Print(TEMPLATE_OF_SET_FUNC_BODY(int32)
, "msg", cpp_name
, "field", f->full_name()
, "lcfield", f->lowercase_name());
break;
case google::protobuf::FieldDescriptor::CPPTYPE_INT64:
impl.Print(TEMPLATE_OF_SET_FUNC_BODY(int64)
, "msg", cpp_name
, "field", f->full_name()
, "lcfield", f->lowercase_name());
break;
case google::protobuf::FieldDescriptor::CPPTYPE_UINT32:
impl.Print(TEMPLATE_OF_SET_FUNC_BODY(uint32)
, "msg", cpp_name
, "field", f->full_name()
, "lcfield", f->lowercase_name());
break;
case google::protobuf::FieldDescriptor::CPPTYPE_UINT64:
impl.Print(TEMPLATE_OF_SET_FUNC_BODY(uint64)
, "msg", cpp_name
, "field", f->full_name()
, "lcfield", f->lowercase_name());
break;
case google::protobuf::FieldDescriptor::CPPTYPE_BOOL:
impl.Print(TEMPLATE_OF_SET_FUNC_BODY(bool)
, "msg", cpp_name
, "field", f->full_name()
, "lcfield", f->lowercase_name());
break;
case google::protobuf::FieldDescriptor::CPPTYPE_FLOAT:
impl.Print(TEMPLATE_OF_SET_FUNC_BODY(float)
, "msg", cpp_name
, "field", f->full_name()
, "lcfield", f->lowercase_name());
break;
case google::protobuf::FieldDescriptor::CPPTYPE_DOUBLE:
impl.Print(TEMPLATE_OF_SET_FUNC_BODY(double)
, "msg", cpp_name
, "field", f->full_name()
, "lcfield", f->lowercase_name());
break;
case google::protobuf::FieldDescriptor::CPPTYPE_ENUM:
impl.Print(
"{\n"
" static_cast<$msg$*>(msg_base)->set_$lcfield$(static_cast<$enum$>(value.as_int32(\"$enum$\")));\n"
" return value.stream()->good();\n"
"}\n"
, "msg", cpp_name
, "enum", to_cpp_name(f->enum_type()->full_name())
, "lcfield", f->lowercase_name());
break;
case google::protobuf::FieldDescriptor::CPPTYPE_STRING:
// TODO: Encoding checking/conversion for pb strings(utf8).
impl.Print(
"{\n"
" if (value.type() == ::mcpack2pb::FIELD_STRING) {\n"
" value.as_string(static_cast<$msg$*>(msg_base)->mutable_$lcfield$(), \"$field$\");\n"
" return value.stream()->good();\n"
" } else if (value.type() == ::mcpack2pb::FIELD_BINARY) {\n"
" value.as_binary(static_cast<$msg$*>(msg_base)->mutable_$lcfield$(), \"$field$\");\n"
" return value.stream()->good();\n"
" }\n"
" LOG(ERROR) << \"Can't set \" << value << \" to $field$ (string)\";\n"
" return false;\n"
"}\n"
, "msg", cpp_name
, "field", f->full_name()
, "lcfield", f->lowercase_name());
break;
case google::protobuf::FieldDescriptor::CPPTYPE_MESSAGE: {
std::string var_name2 = mcpack2pb::to_var_name(f->message_type()->full_name());
ref_msgs.insert(var_name2);
impl.Print(
"{\n"
" if (value.type() == ::mcpack2pb::FIELD_OBJECT) {\n"
" return parse_$vmsg2$_body_internal(static_cast<$msg$*>(msg_base)->mutable_$lcfield$(), value);\n"
" }\n"
, "vmsg2", var_name2
, "msg", cpp_name
, "lcfield", f->lowercase_name());
impl.Print(
// FIXME: describe type.
" LOG(ERROR) << \"Can't set \" << value << \" to $field$\";\n"
" return false;\n"
"}\n"
, "field", f->full_name());
} break;
} // switch
} // else
}
impl.Print(
"bool parse_$vmsg$_body_internal(\n"
" ::google::protobuf::Message* msg,\n"
" ::mcpack2pb::UnparsedValue& value) {\n"
" ::mcpack2pb::ObjectIterator it(value);\n"
" for (; it != NULL; ++it) {\n"
" ::mcpack2pb::SetFieldFn* fn = g_$vmsg$_fields->seek(it->name);\n"
" if (!fn) {\n"
" if (!FLAGS_mcpack2pb_absent_field_is_error) {\n"
" continue;\n"
" } else {\n"
" LOG(ERROR) << \"No field=\" << it->name << \" (\"\n"
" << it->value << \") in $msg$\";\n"
" return false;\n"
" }\n"
" }\n"
" if (!(*fn)(msg, it->value)) {\n"
" return false;\n"
" }\n"
" }\n"
" return value.stream()->good();\n"
"}\n"
"bool parse_$vmsg$_body(\n"
" ::google::protobuf::Message* msg,\n"
" ::google::protobuf::io::ZeroCopyInputStream* input,\n"
" size_t size) {\n"
" ::mcpack2pb::InputStream mc_stream(input);\n"
" ::mcpack2pb::UnparsedValue value(::mcpack2pb::FIELD_OBJECT, &mc_stream, size);\n"
" if (!parse_$vmsg$_body_internal(msg, value)) {\n"
" return false;\n"
" }\n"
" if (!msg->IsInitialized()) {\n"
" LOG(ERROR) << \"Missing required fields: \" << msg->InitializationErrorString();\n"
" return false;\n"
" }\n"
" return true;\n"
"}\n"
"size_t parse_$vmsg$(\n"
" ::google::protobuf::Message* msg,\n"
" ::google::protobuf::io::ZeroCopyInputStream* input) {\n"
" ::mcpack2pb::InputStream mc_stream(input);\n"
" const size_t value_size = ::mcpack2pb::unbox(&mc_stream);\n"
" if (!value_size) {\n"
" LOG(ERROR) << \"Fail to unbox\";\n"
" return 0;\n"
" }\n"
" ::mcpack2pb::UnparsedValue value(::mcpack2pb::FIELD_OBJECT, &mc_stream, value_size);\n"
" if (!parse_$vmsg$_body_internal(msg, value)) {\n"
" return 0;\n"
" }\n"
" if (!msg->IsInitialized()) {\n"
" LOG(ERROR) << \"Missing required fields: \" << msg->InitializationErrorString();\n"
" return 0;\n"
" }\n"
" return 6/*sizeof(FieldLongHead)*/ + value_size;\n"
"}\n"
, "vmsg", var_name
, "msg", d->full_name());
return !impl.failed();
}