diff --git a/src/tools/qtprotobufgen/messagedeclarationprinter.cpp b/src/tools/qtprotobufgen/messagedeclarationprinter.cpp index c74cf015..b07bda5f 100644 --- a/src/tools/qtprotobufgen/messagedeclarationprinter.cpp +++ b/src/tools/qtprotobufgen/messagedeclarationprinter.cpp @@ -98,11 +98,6 @@ void MessageDeclarationPrinter::printComparisonOperators() void MessageDeclarationPrinter::printConstructors() { m_printer->Print(m_typeMap, CommonTemplates::ConstructorMessageDeclarationTemplate()); - - if (m_descriptor->full_name() == "google.protobuf.Timestamp") { - m_printer->Print("Timestamp(const QDateTime &datetime);\n" - "operator QDateTime() const;\n"); - } } void MessageDeclarationPrinter::printMaps() @@ -388,6 +383,14 @@ void MessageDeclarationPrinter::printOneofEnums() }); } +void MessageDeclarationPrinter::printPublicExtras() +{ + if (m_descriptor->full_name() == "google.protobuf.Timestamp") { + m_printer->Print("static Timestamp fromDateTime(const QDateTime &dateTime);\n" + "QDateTime toDateTime() const;\n"); + } +} + void MessageDeclarationPrinter::printClassBody() { printProperties(); @@ -412,6 +415,7 @@ void MessageDeclarationPrinter::printClassBody() Indent(); m_printer->Print(m_typeMap, CommonTemplates::MetaTypeRegistrationDeclaration()); + printPublicExtras(); Outdent(); printPrivateBlock(); diff --git a/src/tools/qtprotobufgen/messagedeclarationprinter.h b/src/tools/qtprotobufgen/messagedeclarationprinter.h index 59ab48cc..7c858245 100644 --- a/src/tools/qtprotobufgen/messagedeclarationprinter.h +++ b/src/tools/qtprotobufgen/messagedeclarationprinter.h @@ -42,6 +42,7 @@ private: void printFieldEnum(); void printQEnums(); void printOneofEnums(); + void printPublicExtras(); //Recursive functionality void printClassDeclarationPrivate(); diff --git a/src/tools/qtprotobufgen/messagedefinitionprinter.cpp b/src/tools/qtprotobufgen/messagedefinitionprinter.cpp index 23d36807..f8d61e53 100644 --- a/src/tools/qtprotobufgen/messagedefinitionprinter.cpp +++ b/src/tools/qtprotobufgen/messagedefinitionprinter.cpp @@ -129,6 +129,7 @@ void MessageDefinitionPrinter::printClassDefinitionPrivate() printMoveSemantic(); printComparisonOperators(); printGetters(); + printPublicExtras(); } void MessageDefinitionPrinter::printClassDefinition() @@ -300,19 +301,6 @@ void MessageDefinitionPrinter::printConstructors() { m_printer->Print(m_typeMap, CommonTemplates::ConstructorMessageDefinitionTemplate()); m_printer->Print(CommonTemplates::EmptyBracesTemplate()); - - if (m_descriptor->full_name() == "google.protobuf.Timestamp") { - m_printer->Print( - "Timestamp::Timestamp(const QDateTime &datetime) : " - "QProtobufMessage(&Timestamp::staticMetaObject)," - "m_seconds(datetime.toMSecsSinceEpoch() / 1000)\n" - ", m_nanos((datetime.toMSecsSinceEpoch() % 1000) * 1000)\n" - "{}\n" - "Timestamp::operator QDateTime() const\n" - "{\n" - " return QDateTime::fromMSecsSinceEpoch(m_seconds * 1000 + m_nanos / 1000);\n" - "}\n"); - } } void MessageDefinitionPrinter::printInitializationList() @@ -475,6 +463,25 @@ void MessageDefinitionPrinter::printDestructor() m_printer->Print(m_typeMap, "$classname$::~$classname$() = default;\n\n"); } +void MessageDefinitionPrinter::printPublicExtras() +{ + if (m_descriptor->full_name() == "google.protobuf.Timestamp") { + m_printer->Print( + "Timestamp Timestamp::fromDateTime(const QDateTime &dateTime)\n" + "{\n" + " Timestamp ts;\n" + " ts.setSeconds(dateTime.toMSecsSinceEpoch() / 1000);\n" + " ts.setNanos((dateTime.toMSecsSinceEpoch() % 1000) * 1000000);\n" + " return ts;\n" + "}\n\n" + "QDateTime Timestamp::toDateTime() const\n" + "{\n" + " return QDateTime::fromMSecsSinceEpoch(\n" + " seconds() * 1000 + nanos() / 1000000, QTimeZone(QTimeZone::UTC));\n" + "}\n\n"); + } +} + void MessageDefinitionPrinter::printClassRegistration(Printer *printer) { if (common::hasNestedMessages(m_descriptor)) { diff --git a/src/tools/qtprotobufgen/messagedefinitionprinter.h b/src/tools/qtprotobufgen/messagedefinitionprinter.h index cd1b0c44..7de5a430 100644 --- a/src/tools/qtprotobufgen/messagedefinitionprinter.h +++ b/src/tools/qtprotobufgen/messagedefinitionprinter.h @@ -43,6 +43,8 @@ private: void printGetters(); void printDestructor(); + void printPublicExtras(); + void printClassDefinitionPrivate(); }; diff --git a/src/tools/qtprotobufgen/qprotobufgenerator.cpp b/src/tools/qtprotobufgen/qprotobufgenerator.cpp index f9ac81c3..bab2d222 100644 --- a/src/tools/qtprotobufgen/qprotobufgenerator.cpp +++ b/src/tools/qtprotobufgen/qprotobufgenerator.cpp @@ -75,6 +75,18 @@ void QProtobufGenerator::GenerateSources(const FileDescriptor *file, registrationPrinter->Print({{"include", basename + CommonTemplates::ProtoFileSuffix()}}, CommonTemplates::InternalIncludeTemplate()); + bool generateWellknownTimestamp = false; + common::iterateMessages(file, [&](const Descriptor *message) { + if (message->full_name() == "google.protobuf.Timestamp") { + generateWellknownTimestamp = true; + return; + } + }); + if (generateWellknownTimestamp) { + sourcePrinter->Print({ { "include", "QtCore/QTimeZone" } }, + CommonTemplates::ExternalIncludeTemplate()); + } + sourcePrinter->Print({{"include", "QtProtobuf/qprotobufserializer.h"}}, CommonTemplates::ExternalIncludeTemplate()); if (Options::instance().hasQml()) { diff --git a/src/wellknown/CMakeLists.txt b/src/wellknown/CMakeLists.txt index 95d92d0f..45c9ecc9 100644 --- a/src/wellknown/CMakeLists.txt +++ b/src/wellknown/CMakeLists.txt @@ -19,7 +19,7 @@ qt_internal_add_protobuf_wellknown_types(ProtobufWellKnownTypes # field_mask # source_context # struct - # timestamp + timestamp # wrappers # type # api diff --git a/tests/auto/protobuf/wellknown/CMakeLists.txt b/tests/auto/protobuf/wellknown/CMakeLists.txt index 7a40afda..ba8a04e1 100644 --- a/tests/auto/protobuf/wellknown/CMakeLists.txt +++ b/tests/auto/protobuf/wellknown/CMakeLists.txt @@ -17,4 +17,20 @@ qt6_add_protobuf(tst_protobuf_any PROTO_INCLUDES $ ) + +qt_internal_add_test(tst_protobuf_timestamp + SOURCES + tst_protobuf_timestamp.cpp + LIBRARIES + Qt::Test + Qt::ProtobufWellKnownTypes +) + +qt6_add_protobuf(tst_protobuf_timestamp + PROTO_FILES + ../../shared/data/proto/timestampmessages.proto + OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/qt_protobuf_generated" + PROTO_INCLUDES + $ +) qt_autogen_tools_initial_setup(tst_protobuf_basictypes_gen) diff --git a/tests/auto/protobuf/wellknown/tst_protobuf_timestamp.cpp b/tests/auto/protobuf/wellknown/tst_protobuf_timestamp.cpp new file mode 100644 index 00000000..e1c5c23c --- /dev/null +++ b/tests/auto/protobuf/wellknown/tst_protobuf_timestamp.cpp @@ -0,0 +1,57 @@ +// Copyright (C) 2023 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +#include "timestampmessages.qpb.h" + +#include + +#include + +#include + +class tst_protobuf_timestamp : public QObject +{ + Q_OBJECT +private slots: + void simpleMessage(); +}; + +using namespace qtproto::tests; +using namespace Qt::StringLiterals; + +void tst_protobuf_timestamp::simpleMessage() +{ + QProtobufSerializer serializer; + + TimestampMessage ts; + ts.setField(google::protobuf::Timestamp::fromDateTime( + { { 1970, 01, 01 }, { 0, 0, 1 }, QTimeZone(QTimeZone::UTC) })); + + QCOMPARE_EQ(ts.field().nanos(), 0); + QCOMPARE_EQ(ts.field().seconds(), 1); + + ts.setField(google::protobuf::Timestamp::fromDateTime( + { { 1984, 6, 8 }, { 10, 10, 10 }, QTimeZone(QTimeZone::UTC) })); + + QCOMPARE_EQ(ts.field().nanos(), 0); + QCOMPARE_EQ(ts.field().seconds(), 455537410); + + QDateTime now = QDateTime::currentDateTime(); + ts.setField(google::protobuf::Timestamp::fromDateTime(now)); + QCOMPARE_EQ(ts.field().toDateTime(), now); + + constexpr auto milliToNano = std::ratio_divide::den; + QCOMPARE_EQ(ts.field().nanos(), (now.toMSecsSinceEpoch() % std::milli::den) * milliToNano); + QCOMPARE_EQ(ts.field().seconds(), now.toMSecsSinceEpoch() / std::milli::den); + + ts.setField(google::protobuf::Timestamp::fromDateTime( + QDateTime::fromMSecsSinceEpoch(1688124178703, QTimeZone(QTimeZone::UTC)))); + QCOMPARE_EQ(ts.serialize(&serializer).toHex(), "0a0c0892f6faa40610c0db9bcf02"_ba); + + QVERIFY(ts.deserialize(&serializer, QByteArray::fromHex("0a0c08c3f7faa4061080d594d603"))); + QCOMPARE_EQ(ts.field().toDateTime(), + QDateTime::fromMSecsSinceEpoch(1688124355986, QTimeZone(QTimeZone::UTC))); +} + +QTEST_MAIN(tst_protobuf_timestamp) +#include "tst_protobuf_timestamp.moc" diff --git a/tests/auto/shared/data/proto/timestampmessages.proto b/tests/auto/shared/data/proto/timestampmessages.proto new file mode 100644 index 00000000..c571ae4f --- /dev/null +++ b/tests/auto/shared/data/proto/timestampmessages.proto @@ -0,0 +1,12 @@ +// Copyright (C) 2023 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only +syntax = "proto3"; + +import "google/protobuf/timestamp.proto"; + +package qtproto.tests; + +message TimestampMessage +{ + google.protobuf.Timestamp field = 1; +}