Re-enable google.protobuf.Timestamp support in well-know types

Enable google.protobuf.Timestamp in well-know types. Add extra
methods that allow convert the generated class from/to QDateTime.

Task-number: QTBUG-114972
Task-number: QTBUG-112430
Change-Id: I00a6878cdd0461f9f0938dd5fa284743df0d8dc8
Reviewed-by: Mårten Nordheim <marten.nordheim@qt.io>
This commit is contained in:
Alexey Edelev 2023-06-30 14:03:36 +02:00
parent 01c3c1c811
commit 4d963586fb
9 changed files with 130 additions and 19 deletions

View File

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

View File

@ -42,6 +42,7 @@ private:
void printFieldEnum();
void printQEnums();
void printOneofEnums();
void printPublicExtras();
//Recursive functionality
void printClassDeclarationPrivate();

View File

@ -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)) {

View File

@ -43,6 +43,8 @@ private:
void printGetters();
void printDestructor();
void printPublicExtras();
void printClassDefinitionPrivate();
};

View File

@ -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()) {

View File

@ -19,7 +19,7 @@ qt_internal_add_protobuf_wellknown_types(ProtobufWellKnownTypes
# field_mask
# source_context
# struct
# timestamp
timestamp
# wrappers
# type
# api

View File

@ -17,4 +17,20 @@ qt6_add_protobuf(tst_protobuf_any
PROTO_INCLUDES
$<TARGET_PROPERTY:Qt6::ProtobufWellKnownTypes,QT_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
$<TARGET_PROPERTY:Qt6::ProtobufWellKnownTypes,QT_PROTO_INCLUDES>
)
qt_autogen_tools_initial_setup(tst_protobuf_basictypes_gen)

View File

@ -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 <QtProtobuf/qprotobufserializer.h>
#include <ratio>
#include <QtTest/QtTest>
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<std::nano, std::milli>::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"

View File

@ -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;
}