Browse Source

Reduce QAbstractProtobufSerializer interface

- Remove "common" functionality of QAbstractProtobufSerializer
- Remove property serialization functions from QAbstractProtobufSerializer
  interface
- Make d-pointer name verbose, Qt-style
- Replace Q_DISABLE_COPY with Q_DISABLE_COPY_MOVE where applicable
Alexey Edelev 5 years ago
parent
commit
2264c52d0d

+ 11 - 11
src/grpc/qabstractgrpcclient.cpp

@@ -46,7 +46,7 @@ public:
 using namespace QtProtobuf;
 
 QAbstractGrpcClient::QAbstractGrpcClient(const QString &service, QObject *parent) : QObject(parent)
-  , d(std::make_unique<QAbstractGrpcClientPrivate>(service))
+  , d_ptr(std::make_unique<QAbstractGrpcClientPrivate>(service))
 {
 }
 
@@ -55,15 +55,15 @@ QAbstractGrpcClient::~QAbstractGrpcClient()
 
 void QAbstractGrpcClient::attachChannel(const std::shared_ptr<QAbstractGrpcChannel> &channel)
 {
-    d->channel = channel;
-    d->serializer = channel->serializer();
+    d_ptr->channel = channel;
+    d_ptr->serializer = channel->serializer();
 }
 
 QGrpcStatus QAbstractGrpcClient::call(const QString &method, const QByteArray &arg, QByteArray &ret)
 {
     QGrpcStatus callStatus{QGrpcStatus::Unknown};
-    if (d->channel) {
-        callStatus = d->channel->call(method, d->service, arg, ret);
+    if (d_ptr->channel) {
+        callStatus = d_ptr->channel->call(method, d_ptr->service, arg, ret);
     } else {
         callStatus = QGrpcStatus{QGrpcStatus::Unknown, QLatin1String("No channel(s) attached.")};
     }
@@ -78,8 +78,8 @@ QGrpcStatus QAbstractGrpcClient::call(const QString &method, const QByteArray &a
 QGrpcAsyncReply *QAbstractGrpcClient::call(const QString &method, const QByteArray &arg)
 {
     QGrpcAsyncReply *reply = nullptr;
-    if (d->channel) {
-        reply = new QGrpcAsyncReply(d->channel, this);
+    if (d_ptr->channel) {
+        reply = new QGrpcAsyncReply(d_ptr->channel, this);
 
         connect(reply, &QGrpcAsyncReply::error, this, [this, reply](const QGrpcStatus &status) {
             error(status);
@@ -90,7 +90,7 @@ QGrpcAsyncReply *QAbstractGrpcClient::call(const QString &method, const QByteArr
             reply->deleteLater();
         });
 
-        d->channel->call(method, d->service, arg, reply);
+        d_ptr->channel->call(method, d_ptr->service, arg, reply);
     } else {
         error({QGrpcStatus::Unknown, QLatin1String("No channel(s) attached.")});
     }
@@ -100,8 +100,8 @@ QGrpcAsyncReply *QAbstractGrpcClient::call(const QString &method, const QByteArr
 
 void QAbstractGrpcClient::subscribe(const QString &method, const QByteArray &arg, const std::function<void(const QByteArray&)> &handler)
 {
-    if (d->channel) {
-        d->channel->subscribe(method, d->service, arg, this, handler);
+    if (d_ptr->channel) {
+        d_ptr->channel->subscribe(method, d_ptr->service, arg, this, handler);
     } else {
         error({QGrpcStatus::Unknown, QLatin1String("No channel(s) attached.")});
     }
@@ -109,6 +109,6 @@ void QAbstractGrpcClient::subscribe(const QString &method, const QByteArray &arg
 
 QAbstractProtobufSerializer *QAbstractGrpcClient::serializer() const
 {
-    return d->serializer.get();
+    return d_ptr->serializer.get();
 }
 

+ 2 - 5
src/grpc/qabstractgrpcclient.h

@@ -204,11 +204,8 @@ private:
         return status;
     }
 
-    Q_DISABLE_COPY(QAbstractGrpcClient)
-    QAbstractGrpcClient(QAbstractGrpcClient &&) = delete;
-    QAbstractGrpcClient &operator =(QAbstractGrpcClient &&) = delete;
+    Q_DISABLE_COPY_MOVE(QAbstractGrpcClient)
 
-    // PIMPL
-    std::unique_ptr<QAbstractGrpcClientPrivate> d;
+    std::unique_ptr<QAbstractGrpcClientPrivate> d_ptr;
 };
 }

+ 1 - 3
src/grpc/qgrpcasyncreply.h

@@ -110,9 +110,7 @@ protected:
 
 private:
     QGrpcAsyncReply();
-    Q_DISABLE_COPY(QGrpcAsyncReply)
-    QGrpcAsyncReply(QGrpcAsyncReply &&) = delete;
-    QGrpcAsyncReply &operator =(QGrpcAsyncReply &&) = delete;
+    Q_DISABLE_COPY_MOVE(QGrpcAsyncReply)
 
     friend class QAbstractGrpcClient;
 

+ 12 - 12
src/grpc/qgrpchttp2channel.cpp

@@ -187,7 +187,7 @@ struct QGrpcHttp2ChannelPrivate {
 }
 
 QGrpcHttp2Channel::QGrpcHttp2Channel(const QUrl &url, const AbstractCredentials &credentials) : QAbstractGrpcChannel()
-  , d(std::make_unique<QGrpcHttp2ChannelPrivate>(url, credentials))
+  , d_ptr(std::make_unique<QGrpcHttp2ChannelPrivate>(url, credentials))
 {
 }
 
@@ -199,7 +199,7 @@ QGrpcStatus QGrpcHttp2Channel::call(const QString &method, const QString &servic
 {
     QEventLoop loop;
 
-    QNetworkReply *networkReply = d->post(method, service, args);
+    QNetworkReply *networkReply = d_ptr->post(method, service, args);
     QObject::connect(networkReply, &QNetworkReply::finished, &loop, &QEventLoop::quit);
 
     //If reply was finished in same stack it doesn't make sense to start event loop
@@ -208,7 +208,7 @@ QGrpcStatus QGrpcHttp2Channel::call(const QString &method, const QString &servic
     }
 
     QGrpcStatus::StatusCode grpcStatus = QGrpcStatus::StatusCode::Unknown;
-    ret = d->processReply(networkReply, grpcStatus);
+    ret = d_ptr->processReply(networkReply, grpcStatus);
 
     qProtoDebug() << __func__ << "RECV: " << ret.toHex() << "grpcStatus" << grpcStatus;
     return {grpcStatus, QString::fromUtf8(networkReply->rawHeader(GrpcStatusMessage))};
@@ -216,7 +216,7 @@ QGrpcStatus QGrpcHttp2Channel::call(const QString &method, const QString &servic
 
 void QGrpcHttp2Channel::call(const QString &method, const QString &service, const QByteArray &args, QtProtobuf::QGrpcAsyncReply *reply)
 {
-    QNetworkReply *networkReply = d->post(method, service, args);
+    QNetworkReply *networkReply = d_ptr->post(method, service, args);
 
     auto connection = QObject::connect(networkReply, &QNetworkReply::finished, reply, [reply, networkReply]() {
         QGrpcStatus::StatusCode grpcStatus = QGrpcStatus::StatusCode::Unknown;
@@ -240,15 +240,15 @@ void QGrpcHttp2Channel::call(const QString &method, const QString &service, cons
 
 void QGrpcHttp2Channel::subscribe(const QString &method, const QString &service, const QByteArray &args, QAbstractGrpcClient *client, const std::function<void (const QByteArray &)> &handler)
 {
-    QNetworkReply *networkReply = d->post(method, service, args, true);
+    QNetworkReply *networkReply = d_ptr->post(method, service, args, true);
 
     auto connection = QObject::connect(networkReply, &QNetworkReply::readyRead, client, [networkReply, handler, this]() {
-        auto replyIt = d->activeStreamReplies.find(networkReply);
+        auto replyIt = d_ptr->activeStreamReplies.find(networkReply);
 
         QByteArray data = networkReply->readAll();
         qProtoDebug() << "RECV" << data.size();
 
-        if (replyIt == d->activeStreamReplies.end()) {
+        if (replyIt == d_ptr->activeStreamReplies.end()) {
             qProtoDebug() << data.toHex();
             int expectedDataSize = qFromBigEndian(*(int *)(data.data() + 1)) + 5;
             qProtoDebug() << "First chunk received: " << data.size() << " expectedDataSize: " << expectedDataSize;
@@ -259,8 +259,8 @@ void QGrpcHttp2Channel::subscribe(const QString &method, const QString &service,
             }
 
             QGrpcHttp2ChannelPrivate::ExpectedData dataContainer{expectedDataSize, QByteArray{}};
-            d->activeStreamReplies.insert({networkReply, dataContainer});
-            replyIt = d->activeStreamReplies.find(networkReply);
+            d_ptr->activeStreamReplies.insert({networkReply, dataContainer});
+            replyIt = d_ptr->activeStreamReplies.find(networkReply);
         }
 
         QGrpcHttp2ChannelPrivate::ExpectedData &dataContainer = replyIt->second;
@@ -270,12 +270,12 @@ void QGrpcHttp2Channel::subscribe(const QString &method, const QString &service,
         if (dataContainer.container.size() == dataContainer.expectedSize) {
             qProtoDebug() << "Full data received: " << data.size() << " dataContainer: " << dataContainer.container.size() << " capacity: " << dataContainer.expectedSize;
             handler(dataContainer.container.mid(5));
-            d->activeStreamReplies.erase(replyIt);
+            d_ptr->activeStreamReplies.erase(replyIt);
         }
     });
 
     QObject::connect(client, &QAbstractGrpcClient::destroyed, networkReply, [networkReply, connection, this]() {
-        d->activeStreamReplies.erase(networkReply);
+        d_ptr->activeStreamReplies.erase(networkReply);
         QObject::disconnect(connection);
         QGrpcHttp2ChannelPrivate::abortNetworkReply(networkReply);
     });
@@ -283,7 +283,7 @@ void QGrpcHttp2Channel::subscribe(const QString &method, const QString &service,
     //TODO: seems this connection might be invalid in case if this destroyed.
     //Think about correct handling of this situation
     QObject::connect(networkReply, &QNetworkReply::finished, [networkReply, connection, this]() {
-        d->activeStreamReplies.erase(networkReply);
+        d_ptr->activeStreamReplies.erase(networkReply);
         //TODO: implement error handling and subscription recovery here
         QObject::disconnect(connection);
         QGrpcHttp2ChannelPrivate::abortNetworkReply(networkReply);

+ 2 - 5
src/grpc/qgrpchttp2channel.h

@@ -53,11 +53,8 @@ protected:
     void abort(QGrpcAsyncReply *reply) override;
 
 private:
-    Q_DISABLE_COPY(QGrpcHttp2Channel)
-    QGrpcHttp2Channel(QGrpcHttp2Channel &&) = delete;
-    QGrpcHttp2Channel &operator =(QGrpcHttp2Channel &&) = delete;
+    Q_DISABLE_COPY_MOVE(QGrpcHttp2Channel)
 
-    // PIMPL
-    std::unique_ptr<QGrpcHttp2ChannelPrivate> d;
+    std::unique_ptr<QGrpcHttp2ChannelPrivate> d_ptr;
 };
 }

+ 11 - 11
src/grpc/qgrpcstatus.cpp

@@ -40,26 +40,26 @@ public:
 };
 
 QGrpcStatus::QGrpcStatus(StatusCode code, const QString &message) :
-    d(std::make_unique<QGrpcStatusPrivate>(code, message))
+    d_ptr(std::make_unique<QGrpcStatusPrivate>(code, message))
 {}
 
-QGrpcStatus::QGrpcStatus(const QGrpcStatus &other) : d(std::make_unique<QGrpcStatusPrivate>(other.d->m_code, other.d->m_message))
+QGrpcStatus::QGrpcStatus(const QGrpcStatus &other) : d_ptr(std::make_unique<QGrpcStatusPrivate>(other.d_ptr->m_code, other.d_ptr->m_message))
 {}
 
-QGrpcStatus::QGrpcStatus(QGrpcStatus &&other) : d(std::move(other.d))
+QGrpcStatus::QGrpcStatus(QGrpcStatus &&other) : d_ptr(std::move(other.d_ptr))
 {
 }
 
 QGrpcStatus &QGrpcStatus::operator =(const QGrpcStatus &other)
 {
-    d->m_code = other.d->m_code;
-    d->m_message = other.d->m_message;
+    d_ptr->m_code = other.d_ptr->m_code;
+    d_ptr->m_message = other.d_ptr->m_message;
     return *this;
 }
 
 QGrpcStatus &QGrpcStatus::operator =(QGrpcStatus &&other)
 {
-    d = std::move(other.d);
+    d_ptr = std::move(other.d_ptr);
     return *this;
 }
 
@@ -68,27 +68,27 @@ QGrpcStatus::~QGrpcStatus()
 
 QString QGrpcStatus::message() const
 {
-    return d->m_message;
+    return d_ptr->m_message;
 }
 
 QGrpcStatus::StatusCode QGrpcStatus::code() const
 {
-    return d->m_code;
+    return d_ptr->m_code;
 }
 
 bool QGrpcStatus::operator ==(StatusCode code) const
 {
-    return d->m_code == code;
+    return d_ptr->m_code == code;
 }
 
 bool QGrpcStatus::operator !=(StatusCode code) const
 {
-    return d->m_code != code;
+    return d_ptr->m_code != code;
 }
 
 bool QGrpcStatus::operator ==(const QGrpcStatus &other) const
 {
-    return d->m_code == other.d->m_code;
+    return d_ptr->m_code == other.d_ptr->m_code;
 }
 
 }

+ 1 - 1
src/grpc/qgrpcstatus.h

@@ -92,7 +92,7 @@ public:
     QGrpcStatus &operator =(QGrpcStatus &&other);
 
 private:
-    std::unique_ptr<QGrpcStatusPrivate> d;
+    std::unique_ptr<QGrpcStatusPrivate> d_ptr;
 };
 }
 

+ 14 - 0
src/grpc/qtgrpcglobal.h

@@ -32,3 +32,17 @@
 #else
     #define Q_GRPC_EXPORT Q_DECL_IMPORT
 #endif
+
+//Support macro for Qt versions < 5.13
+//TODO: remove once migration to 5.14 as minimum required version is completed
+#ifndef Q_DISABLE_MOVE
+    #define Q_DISABLE_MOVE(Class) \
+        Class(Class &&) = delete; \
+        Class &operator=(Class &&) = delete;
+#endif
+
+#ifndef Q_DISABLE_COPY_MOVE
+#define Q_DISABLE_COPY_MOVE(Class) \
+    Q_DISABLE_COPY(Class) \
+    Q_DISABLE_MOVE(Class)
+#endif

+ 0 - 23
src/protobuf/qabstractprotobufserializer.cpp

@@ -53,26 +53,3 @@ QtProtobufPrivate::SerializationHandler &QtProtobufPrivate::findHandler(int user
     }
     return empty;
 }
-
-QByteArray QAbstractProtobufSerializer::serializeObjectCommon(const QObject *object, const QProtobufPropertyOrdering &propertyOrdering, const QMetaObject &metaObject) const
-{
-    QByteArray result;
-    for (const auto &field : propertyOrdering) {
-        int propertyIndex = field.second;
-        int fieldIndex = field.first;
-        Q_ASSERT_X(fieldIndex < 536870912 && fieldIndex > 0, "", "fieldIndex is out of range");
-        QMetaProperty metaProperty = metaObject.property(propertyIndex);
-        const char *propertyName = metaProperty.name();
-        const QVariant &propertyValue = object->property(propertyName);
-        result.append(serializeProperty(propertyValue, fieldIndex, metaProperty));
-    }
-
-    return result;
-}
-
-void QAbstractProtobufSerializer::deserializeObjectCommon(QObject *object, const QByteArray &data, const QProtobufPropertyOrdering &propertyOrdering, const QMetaObject &metaObject) const
-{
-    for (QProtobufSelfcheckIterator it(data); it != data.end();) {
-        deserializeProperty(object, it, propertyOrdering, metaObject);
-    }
-}

+ 0 - 41
src/protobuf/qabstractprotobufserializer.h

@@ -119,25 +119,6 @@ public:
      */
     virtual void deserializeMessage(QObject *object, const QByteArray &data, const QProtobufPropertyOrdering &propertyOrdering, const QMetaObject &metaObject) const = 0;
 
-    /*!
-     * \brief serializeProperty Method called on property serialization cycle.
-     * \param[in] propertyValue Value of property and metainformation stored in QVariant
-     * \param[in] fieldIndex index of property in message
-     * \param[in] metaProperty meta information about property to be serialized
-     * \return Raw serialized data represented as byte array
-     */
-    virtual QByteArray serializeProperty(const QVariant &propertyValue, int fieldIndex, const QMetaProperty &metaProperty) const = 0;
-
-    /*!
-     * \brief deserializeProperty Method called on property deserialization cycle
-     * \param[out] object Property value will be written to the given QObject.
-     * \param[in] it Pointer to next chunk of raw data received from channel
-     * \param[in] propertyOrdering Ordering of properties for given \a object
-     * \param[in] metaObject Static meta object of given \a object. Static meta object usualy is used to get actual
-     *            property value and write new property to \a object
-     */
-    virtual void deserializeProperty(QObject *object, QProtobufSelfcheckIterator &it, const QProtobufPropertyOrdering &propertyOrdering, const QMetaObject &metaObject) const = 0;
-
     /*!
      * \brief serializeObject Serializes complete \a object according given \a propertyOrdering and \a metaObject
      *        information
@@ -200,28 +181,6 @@ public:
      * \see https://developers.google.com/protocol-buffers/docs/proto3#maps for details
      */
     virtual void deserializeMapPair(QVariant &key, QVariant &value, QProtobufSelfcheckIterator &it) const = 0;
-
-protected:
-    /*!
-     * \brief serializeObjectCommon Common routine to iterate object properties. Could be used in serializer
-     *        implementations. But in practice is private interface for QAbstractProtobufSerializer
-     * \param[in] object Pointer to object to be serialized
-     * \param[in] propertyOrdering Ordering of properties for given \a object
-     * \param[in] metaObject Static meta object of given \a object.
-     * \return Raw serialized data represented as byte array
-     */
-    QByteArray serializeObjectCommon(const QObject *object, const QProtobufPropertyOrdering &propertyOrdering, const QMetaObject &metaObject) const;
-
-    /*!
-     * \brief deserializeObjectCommon Common routine to iterate object properties. Could be used in serializer
-     *        implementations. But in practice is private interface for QAbstractProtobufSerializer
-     * \param[out] object Pointer to allocated object
-     * \param[in] array Complete message buffer received from transport stream
-     * \param[in] propertyOrdering Ordering of properties for given \a object
-     * \param[in] metaObject Static meta object of given \a object. Static meta object usualy is used to get actual
-     *        property value and write new property to \a object
-     */
-    void deserializeObjectCommon(QObject *object, const QByteArray &array, const QProtobufPropertyOrdering &propertyOrdering, const QMetaObject &metaObject) const;
 };
 /*! \} */
 }

+ 41 - 23
src/protobuf/qprotobufjsonserializer.cpp

@@ -28,14 +28,52 @@
 
 using namespace QtProtobuf;
 
-QProtobufJsonSerializer::QProtobufJsonSerializer()
+namespace QtProtobuf {
+
+class QProtobufJsonSerializerPrivate final
+{
+    Q_DISABLE_COPY_MOVE(QProtobufJsonSerializerPrivate)
+public:
+    QProtobufJsonSerializerPrivate(QProtobufJsonSerializer *q) : q_ptr(q) {}
+    ~QProtobufJsonSerializerPrivate() = default;
+
+    QByteArray serializeProperty(const QVariant &propertyValue, int fieldIndex, const QMetaProperty &metaProperty) {
+        Q_UNUSED(fieldIndex)
+        auto &value = QtProtobufPrivate::findHandler(metaProperty.userType());
+        if (value.serializer) {
+            return value.serializer(q_ptr, propertyValue, fieldIndex);
+        } else {
+            QString result("\"%1\":%2");
+            return result.arg(metaProperty.name(), propertyValue.toString()).toUtf8();
+        }
+    }
+private:
+    QProtobufJsonSerializer *q_ptr;
+};
+
+}
+
+QProtobufJsonSerializer::QProtobufJsonSerializer() : d_ptr(new QProtobufJsonSerializerPrivate(this))
 {
 }
 
+QProtobufJsonSerializer::~QProtobufJsonSerializer() = default;
+
+
 QByteArray QProtobufJsonSerializer::serializeMessage(const QObject *object, const QProtobufPropertyOrdering &propertyOrdering, const QMetaObject &metaObject) const
 {
     QByteArray result = "{";
-    result.append(serializeObjectCommon(object, propertyOrdering, metaObject));
+
+    for (const auto &field : propertyOrdering) {
+        int propertyIndex = field.second;
+        int fieldIndex = field.first;
+        Q_ASSERT_X(fieldIndex < 536870912 && fieldIndex > 0, "", "fieldIndex is out of range");
+        QMetaProperty metaProperty = metaObject.property(propertyIndex);
+        const char *propertyName = metaProperty.name();
+        const QVariant &propertyValue = object->property(propertyName);
+        result.append(d_ptr->serializeProperty(propertyValue, fieldIndex, metaProperty));
+    }
+
     result.append("}");
     return result;
 }
@@ -48,30 +86,10 @@ void QProtobufJsonSerializer::deserializeMessage(QObject *object, const QByteArr
     Q_UNUSED(metaObject)
 }
 
-QByteArray QProtobufJsonSerializer::serializeProperty(const QVariant &propertyValue, int fieldIndex, const QMetaProperty &metaProperty) const
-{
-    Q_UNUSED(fieldIndex)
-    auto &value = QtProtobufPrivate::findHandler(metaProperty.userType());
-    if (value.serializer) {
-        return value.serializer(this, propertyValue, fieldIndex);
-    } else {
-        QString result("\"%1\":%2");
-        return result.arg(metaProperty.name(), propertyValue.toString()).toUtf8();
-    }
-}
-
-void QProtobufJsonSerializer::deserializeProperty(QObject *object, QProtobufSelfcheckIterator &it, const QProtobufPropertyOrdering &propertyOrdering, const QMetaObject &metaObject) const
-{
-    Q_UNUSED(object)
-    Q_UNUSED(it)
-    Q_UNUSED(propertyOrdering)
-    Q_UNUSED(metaObject)
-}
-
 QByteArray QProtobufJsonSerializer::serializeObject(const QObject *object, const QProtobufPropertyOrdering &propertyOrdering, const QMetaObject &metaObject) const
 {
     QByteArray result = "{";
-    result.append(serializeObjectCommon(object, propertyOrdering, metaObject));
+    result.append(serializeMessage(object, propertyOrdering, metaObject));
     result.append("}");
     return result;
 }

+ 6 - 4
src/protobuf/qprotobufjsonserializer.h

@@ -26,7 +26,10 @@
 #include "qabstractprotobufserializer.h"
 #include "qtprotobufglobal.h"
 
+#include <memory>
+
 namespace QtProtobuf {
+class QProtobufJsonSerializerPrivate;
 /*!
 *  \ingroup QtProtobuf
  * \brief The QProtobufJsonSerializer class
@@ -35,15 +38,12 @@ class Q_PROTOBUF_EXPORT QProtobufJsonSerializer : public QAbstractProtobufSerial
 {
 public:
     QProtobufJsonSerializer();
-    ~QProtobufJsonSerializer() = default;
+    ~QProtobufJsonSerializer();
 
 protected:
     QByteArray serializeMessage(const QObject *object, const QProtobufPropertyOrdering &propertyOrdering, const QMetaObject &metaObject) const  override;
     void deserializeMessage(QObject *object, const QByteArray &data, const QProtobufPropertyOrdering &propertyOrdering, const QMetaObject &metaObject) const override;
 
-    QByteArray serializeProperty(const QVariant &propertyValue, int fieldIndex, const QMetaProperty &metaProperty) const override;
-    void deserializeProperty(QObject *object, QProtobufSelfcheckIterator &it, const QProtobufPropertyOrdering &propertyOrdering, const QMetaObject &metaObject) const override;
-
     QByteArray serializeObject(const QObject *object, const QProtobufPropertyOrdering &propertyOrdering, const QMetaObject &metaObject) const override;
     void deserializeObject(QObject *object, QProtobufSelfcheckIterator &it, const QProtobufPropertyOrdering &propertyOrdering, const QMetaObject &metaObject) const override;
 
@@ -52,6 +52,8 @@ protected:
 
     QByteArray serializeMapPair(const QVariant &key, const QVariant &value, int fieldIndex) const override;
     void deserializeMapPair(QVariant &key, QVariant &value, QProtobufSelfcheckIterator &it) const override;
+private:
+    std::unique_ptr<QProtobufJsonSerializerPrivate> d_ptr;
 };
 
 }

+ 97 - 77
src/protobuf/qprotobufserializer.cpp

@@ -32,7 +32,7 @@ using namespace QtProtobuf;
 
 QProtobufSerializer::~QProtobufSerializer() = default;
 
-QProtobufSerializer::QProtobufSerializer()
+QProtobufSerializer::QProtobufSerializer() : d_ptr(new QProtobufSerializerPrivate(this))
 {
     QProtobufSerializerPrivate::wrapSerializer<float>(QProtobufSerializerPrivate::serializeBasic<float>, QProtobufSerializerPrivate::deserializeBasic<float>, Fixed32);
     QProtobufSerializerPrivate::wrapSerializer<double>(QProtobufSerializerPrivate::serializeBasic<double>, QProtobufSerializerPrivate::deserializeBasic<double>, Fixed64);
@@ -69,98 +69,36 @@ QProtobufSerializer::QProtobufSerializer()
 
 QByteArray QProtobufSerializer::serializeMessage(const QObject *object, const QProtobufPropertyOrdering &propertyOrdering, const QMetaObject &metaObject) const
 {
-    return serializeObjectCommon(object, propertyOrdering, metaObject);
-}
-
-void QProtobufSerializer::deserializeMessage(QObject *object, const QByteArray &data, const QProtobufPropertyOrdering &propertyOrdering, const QMetaObject &metaObject) const
-{
-    deserializeObjectCommon(object, data, propertyOrdering, metaObject);
-}
-
-QByteArray QProtobufSerializer::serializeProperty(const QVariant &propertyValue, int fieldIndex, const QMetaProperty &metaProperty) const
-{
-    qProtoDebug() << __func__ << "propertyValue" << propertyValue << "fieldIndex" << fieldIndex
-                  << static_cast<QMetaType::Type>(propertyValue.type());
-
     QByteArray result;
-    WireTypes type = UnknownWireType;
-
-    int userType = propertyValue.userType();
-    if (metaProperty.isEnumType()) {
-        userType = qMetaTypeId<int64>();
+    for (const auto &field : propertyOrdering) {
+        int propertyIndex = field.second;
+        int fieldIndex = field.first;
+        Q_ASSERT_X(fieldIndex < 536870912 && fieldIndex > 0, "", "fieldIndex is out of range");
+        QMetaProperty metaProperty = metaObject.property(propertyIndex);
+        const char *propertyName = metaProperty.name();
+        const QVariant &propertyValue = object->property(propertyName);
+        result.append(d_ptr->serializeProperty(propertyValue, fieldIndex, metaProperty));
     }
 
-    //TODO: replace with some common function
-    auto basicIt = QProtobufSerializerPrivate::handlers.find(userType);
-    if (basicIt != QProtobufSerializerPrivate::handlers.end()) {
-        type = basicIt->second.type;
-        result.append(basicIt->second.serializer(propertyValue, fieldIndex));
-    } else {
-        auto &handler = QtProtobufPrivate::findHandler(userType);
-        type = handler.type;
-        result.append(handler.serializer(this, propertyValue, fieldIndex));//throws if not implemented
-    }
-
-    if (fieldIndex != QtProtobufPrivate::NotUsedFieldIndex
-            && type != UnknownWireType) {
-        result.prepend(QProtobufSerializerPrivate::encodeHeader(fieldIndex, type));
-    }
     return result;
 }
 
-void QProtobufSerializer::deserializeProperty(QObject *object, QProtobufSelfcheckIterator &it, const QProtobufPropertyOrdering &propertyOrdering, const QMetaObject &metaObject) const
+void QProtobufSerializer::deserializeMessage(QObject *object, const QByteArray &data, const QProtobufPropertyOrdering &propertyOrdering, const QMetaObject &metaObject) const
 {
-    //Each iteration we expect iterator is setup to beginning of next chunk
-    int fieldNumber = QtProtobufPrivate::NotUsedFieldIndex;
-    WireTypes wireType = UnknownWireType;
-    if (!QProtobufSerializerPrivate::decodeHeader(it, fieldNumber, wireType)) {
-        qProtoCritical() << "Message received doesn't contains valid header byte. "
-                            "Trying next, but seems stream is broken" << QString::number((*it), 16);
-        throw std::invalid_argument("Message received doesn't contains valid header byte. "
-                              "Seems stream is broken");
-    }
-
-    auto propertyNumberIt = propertyOrdering.find(fieldNumber);
-    if (propertyNumberIt == std::end(propertyOrdering)) {
-        auto bytesCount = QProtobufSerializerPrivate::skipSerializedFieldBytes(it, wireType);
-        qProtoWarning() << "Message received contains unexpected/optional field. WireType:" << wireType
-                        << ", field number: " << fieldNumber << "Skipped:" << (bytesCount + 1) << "bytes";
-        return;
-    }
-
-    int propertyIndex = propertyNumberIt->second;
-    QMetaProperty metaProperty = metaObject.property(propertyIndex);
-
-    qProtoDebug() << __func__ << " wireType: " << wireType << " metaProperty: " << metaProperty.typeName()
-                  << "currentByte:" << QString::number((*it), 16);
-
-    QVariant newPropertyValue;
-    if (metaProperty.isEnumType()) {
-        newPropertyValue = QVariant::fromValue(int32_t(QProtobufSerializerPrivate::deserializeBasic<int64>(it).value<int64>()._t));
-    } else {
-        newPropertyValue = metaProperty.read(object);
-        int userType = metaProperty.userType();
-        //TODO: replace with some common function
-        auto basicIt = QProtobufSerializerPrivate::handlers.find(userType);
-        if (basicIt != QProtobufSerializerPrivate::handlers.end()) {
-            basicIt->second.deserializer(it, newPropertyValue);
-        } else {
-            auto &handler = QtProtobufPrivate::findHandler(userType);
-            handler.deserializer(this, it, newPropertyValue);//throws if not implemented
-        }
+    for (QProtobufSelfcheckIterator it(data); it != data.end();) {
+        d_ptr->deserializeProperty(object, it, propertyOrdering, metaObject);
     }
-    metaProperty.write(object, newPropertyValue);
 }
 
 QByteArray QProtobufSerializer::serializeObject(const QObject *object, const QProtobufPropertyOrdering &propertyOrdering, const QMetaObject &metaObject) const
 {
-    return QProtobufSerializerPrivate::prependLengthDelimitedSize(serializeObjectCommon(object, propertyOrdering, metaObject));
+    return QProtobufSerializerPrivate::prependLengthDelimitedSize(serializeMessage(object, propertyOrdering, metaObject));
 }
 
 void QProtobufSerializer::deserializeObject(QObject *object, QProtobufSelfcheckIterator &it, const QProtobufPropertyOrdering &propertyOrdering, const QMetaObject &metaObject) const
 {
     QByteArray array = QProtobufSerializerPrivate::deserializeLengthDelimited(it);
-    deserializeObjectCommon(object, array, propertyOrdering, metaObject);
+    deserializeMessage(object, array, propertyOrdering, metaObject);
 }
 
 QByteArray QProtobufSerializer::serializeListObject(const QObject *object, const QProtobufPropertyOrdering &propertyOrdering, const QMetaObject &metaObject, int fieldIndex) const
@@ -178,7 +116,7 @@ void QProtobufSerializer::deserializeListObject(QObject *object, QProtobufSelfch
 QByteArray QProtobufSerializer::serializeMapPair(const QVariant &key, const QVariant &value, int fieldIndex) const
 {
     QByteArray result = QProtobufSerializerPrivate::encodeHeader(fieldIndex, LengthDelimited);
-    result.append(QProtobufSerializerPrivate::prependLengthDelimitedSize(serializeProperty(key, 1, QMetaProperty()) + serializeProperty(value, 2, QMetaProperty())));
+    result.append(QProtobufSerializerPrivate::prependLengthDelimitedSize(d_ptr->serializeProperty(key, 1, QMetaProperty()) + d_ptr->serializeProperty(value, 2, QMetaProperty())));
     return result;
 }
 
@@ -215,6 +153,12 @@ void QProtobufSerializer::deserializeMapPair(QVariant &key, QVariant &value, QPr
     }
 }
 
+
+QProtobufSerializerPrivate::QProtobufSerializerPrivate(QProtobufSerializer *q) : q_ptr(q)
+{
+
+}
+
 void QProtobufSerializerPrivate::skipVarint(QProtobufSelfcheckIterator &it)
 {
     while ((*it) & 0x80) {
@@ -254,4 +198,80 @@ int QProtobufSerializerPrivate::skipSerializedFieldBytes(QProtobufSelfcheckItera
     return std::distance(initialIt, QByteArray::const_iterator(it));
 }
 
+
+QByteArray QProtobufSerializerPrivate::serializeProperty(const QVariant &propertyValue, int fieldIndex, const QMetaProperty &metaProperty)
+{
+    qProtoDebug() << __func__ << "propertyValue" << propertyValue << "fieldIndex" << fieldIndex
+                  << static_cast<QMetaType::Type>(propertyValue.type());
+
+    QByteArray result;
+    WireTypes type = UnknownWireType;
+
+    int userType = propertyValue.userType();
+    if (metaProperty.isEnumType()) {
+        userType = qMetaTypeId<int64>();
+    }
+
+    //TODO: replace with some common function
+    auto basicIt = QProtobufSerializerPrivate::handlers.find(userType);
+    if (basicIt != QProtobufSerializerPrivate::handlers.end()) {
+        type = basicIt->second.type;
+        result.append(basicIt->second.serializer(propertyValue, fieldIndex));
+    } else {
+        auto &handler = QtProtobufPrivate::findHandler(userType);
+        type = handler.type;
+        result.append(handler.serializer(q_ptr, propertyValue, fieldIndex));//throws if not implemented
+    }
+
+    if (fieldIndex != QtProtobufPrivate::NotUsedFieldIndex
+            && type != UnknownWireType) {
+        result.prepend(QProtobufSerializerPrivate::encodeHeader(fieldIndex, type));
+    }
+    return result;
+}
+
+void QProtobufSerializerPrivate::deserializeProperty(QObject *object, QProtobufSelfcheckIterator &it, const QProtobufPropertyOrdering &propertyOrdering, const QMetaObject &metaObject)
+{
+    //Each iteration we expect iterator is setup to beginning of next chunk
+    int fieldNumber = QtProtobufPrivate::NotUsedFieldIndex;
+    WireTypes wireType = UnknownWireType;
+    if (!QProtobufSerializerPrivate::decodeHeader(it, fieldNumber, wireType)) {
+        qProtoCritical() << "Message received doesn't contains valid header byte. "
+                            "Trying next, but seems stream is broken" << QString::number((*it), 16);
+        throw std::invalid_argument("Message received doesn't contains valid header byte. "
+                              "Seems stream is broken");
+    }
+
+    auto propertyNumberIt = propertyOrdering.find(fieldNumber);
+    if (propertyNumberIt == std::end(propertyOrdering)) {
+        auto bytesCount = QProtobufSerializerPrivate::skipSerializedFieldBytes(it, wireType);
+        qProtoWarning() << "Message received contains unexpected/optional field. WireType:" << wireType
+                        << ", field number: " << fieldNumber << "Skipped:" << (bytesCount + 1) << "bytes";
+        return;
+    }
+
+    int propertyIndex = propertyNumberIt->second;
+    QMetaProperty metaProperty = metaObject.property(propertyIndex);
+
+    qProtoDebug() << __func__ << " wireType: " << wireType << " metaProperty: " << metaProperty.typeName()
+                  << "currentByte:" << QString::number((*it), 16);
+
+    QVariant newPropertyValue;
+    if (metaProperty.isEnumType()) {
+        newPropertyValue = QVariant::fromValue(int32_t(QProtobufSerializerPrivate::deserializeBasic<int64>(it).value<int64>()._t));
+    } else {
+        newPropertyValue = metaProperty.read(object);
+        int userType = metaProperty.userType();
+        //TODO: replace with some common function
+        auto basicIt = QProtobufSerializerPrivate::handlers.find(userType);
+        if (basicIt != QProtobufSerializerPrivate::handlers.end()) {
+            basicIt->second.deserializer(it, newPropertyValue);
+        } else {
+            auto &handler = QtProtobufPrivate::findHandler(userType);
+            handler.deserializer(q_ptr, it, newPropertyValue);//throws if not implemented
+        }
+    }
+    metaProperty.write(object, newPropertyValue);
+}
+
 QProtobufSerializerPrivate::SerializerRegistry QProtobufSerializerPrivate::handlers = {};

+ 1 - 5
src/protobuf/qprotobufserializer.h

@@ -45,9 +45,6 @@ protected:
     QByteArray serializeMessage(const QObject *object, const QProtobufPropertyOrdering &propertyOrdering, const QMetaObject &metaObject) const override;
     void deserializeMessage(QObject *object, const QByteArray &data, const QProtobufPropertyOrdering &propertyOrdering, const QMetaObject &metaObject) const override;
 
-    QByteArray serializeProperty(const QVariant &propertyValue, int fieldIndex, const QMetaProperty &metaProperty) const override;
-    void deserializeProperty(QObject *object, QProtobufSelfcheckIterator &it, const QProtobufPropertyOrdering &propertyOrdering, const QMetaObject &metaObject) const override;
-
     QByteArray serializeObject(const QObject *object, const QProtobufPropertyOrdering &propertyOrdering, const QMetaObject &metaObject) const override;
     void deserializeObject(QObject *object, QProtobufSelfcheckIterator &it, const QProtobufPropertyOrdering &propertyOrdering, const QMetaObject &metaObject) const override;
 
@@ -57,8 +54,7 @@ protected:
     QByteArray serializeMapPair(const QVariant &key, const QVariant &value, int fieldIndex) const override;
     void deserializeMapPair(QVariant &key, QVariant &value, QProtobufSelfcheckIterator &it) const override;
 
-private:
-    std::unique_ptr<QProtobufSerializerPrivate> d;
+    std::unique_ptr<QProtobufSerializerPrivate> d_ptr;
 };
 
 }

+ 10 - 5
src/protobuf/qprotobufserializer_p.h

@@ -40,10 +40,9 @@ namespace QtProtobuf {
  */
 class QProtobufSerializer;
 
-class QProtobufSerializerPrivate final {
-    Q_DISABLE_COPY(QProtobufSerializerPrivate)
-    QProtobufSerializerPrivate(QProtobufSerializerPrivate &&) = delete;
-    QProtobufSerializerPrivate &operator =(QProtobufSerializerPrivate &&) = delete;
+class QProtobufSerializerPrivate final
+{
+    Q_DISABLE_COPY_MOVE(QProtobufSerializerPrivate)
 public:
 
     /*!
@@ -66,7 +65,7 @@ public:
 
     using SerializerRegistry = std::unordered_map<int/*metatypeid*/, SerializationHandlers>;
 
-    QProtobufSerializerPrivate();
+    QProtobufSerializerPrivate(QProtobufSerializer *q);
     ~QProtobufSerializerPrivate() = default;
     //###########################################################################
     //                               Serializers
@@ -478,6 +477,12 @@ public:
     static SerializerRegistry handlers;
     static void skipVarint(QProtobufSelfcheckIterator &it);
     static void skipLengthDelimited(QProtobufSelfcheckIterator &it);
+
+    QByteArray serializeProperty(const QVariant &propertyValue, int fieldIndex, const QMetaProperty &metaProperty);
+    void deserializeProperty(QObject *object, QProtobufSelfcheckIterator &it, const QProtobufPropertyOrdering &propertyOrdering, const QMetaObject &metaObject);
+
+private:
+    QProtobufSerializer *q_ptr;
 };
 
 //###########################################################################

+ 13 - 0
src/protobuf/qprotobufserializerregistry.cpp

@@ -27,6 +27,19 @@
 #include "qprotobufserializer.h"
 #include "qprotobufjsonserializer.h"
 
+#include <QString>
+#include <QHash>
+
+//TODO: remove once migration to 5.14 as minimum required version is completed
+#if QT_VERSION < 0x051300
+namespace std {
+  template<> struct hash<QString> {
+    std::size_t operator()(const QString &s) const {
+      return std::hash<std::string>()(s.toStdString());
+    }
+  };
+}
+#endif
 
 namespace QtProtobuf {
 class QProtobufSerializerRegistryPrivate {

+ 14 - 0
src/protobuf/qtprotobufglobal.h

@@ -32,3 +32,17 @@
 #else
 #  define Q_PROTOBUF_EXPORT Q_DECL_IMPORT
 #endif
+
+//Support macro for Qt versions < 5.13
+//TODO: remove once migration to 5.14 as minimum required version is completed
+#ifndef Q_DISABLE_MOVE
+    #define Q_DISABLE_MOVE(Class) \
+        Class(Class &&) = delete; \
+        Class &operator=(Class &&) = delete;
+#endif
+
+#ifndef Q_DISABLE_COPY_MOVE
+#define Q_DISABLE_COPY_MOVE(Class) \
+    Q_DISABLE_COPY(Class) \
+    Q_DISABLE_MOVE(Class)
+#endif