static bool generate_parsing()

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();
}