static bool generate_serializing()

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