Browse Source

Complete protobuf object refactoring

- ProtobufObject now only keeps serializers/deserializers
- Extract ProtobufObjectPrivate from ProtobufObject
- Complete migratation to new transparent types
TODO: Add all serializers used in serializeUserType to serializers member
      Add all deserialiers used in deserializeUserType to serializers member
Alexey Edelev 6 years ago
parent
commit
8d5199818d

+ 3 - 1
src/protobuf/CMakeLists.txt

@@ -9,11 +9,13 @@ if(Qt5_POSITION_INDEPENDENT_CODE)
 endif()
 
 file(GLOB SOURCES
-    protobufobject.cpp
+    protobufobject_p.cpp
     qtprotobuf.cpp
     qtprotobuflogging.cpp)
 
 file(GLOB HEADERS
+    protobufobject_p.inc
+    protobufobject_p.h
     protobufobject.h
     qtprotobuftypes.h
     qtprotobuf.h)

+ 13 - 91
src/protobuf/protobufobject.h

@@ -25,108 +25,30 @@
 
 #pragma once
 
-#include "protobufobject_p.h"
-
-#include <QMetaObject>
-#include <QMetaProperty>
-
-#include <unordered_map>
-#include <memory>
-#include <type_traits>
-#include <typeinfo>
-#include <functional>
-
-#include <qtprotobuftypes.h>
-#include <qtprotobuflogging.h>
-
-#define ASSERT_FIELD_NUMBER(X) Q_ASSERT_X(X < 128 && X > 0 && X != NotUsedFieldIndex, T::staticMetaObject.className(), "fieldIndex is out of range")
+#include <QObject>
+#include <QByteArray>
+#include <QVariant>
 
 namespace qtprotobuf {
 
 template <typename T>
-class ProtobufObject : public ProtobufObjectPrivate
+class ProtobufObject : public QObject
 {
 public:
-    explicit ProtobufObject(QObject *parent = nullptr) : ProtobufObjectPrivate(parent) {}
-
-    QByteArray serialize() const {
-        qProtoDebug() << T::staticMetaObject.className() << "serialize";
-
-        QByteArray result;
-        const QObject *instance = static_cast<const QObject *>(this);
-        for (auto field : T::propertyOrdering) {
-            int propertyIndex = field.second;
-            int fieldIndex = field.first;
-            ASSERT_FIELD_NUMBER(fieldIndex);
-            QMetaProperty metaProperty = T::staticMetaObject.property(propertyIndex);
-            const char *propertyName = metaProperty.name();
-            const QVariant &propertyValue = instance->property(propertyName);
-            result.append(serializeValue(propertyValue, fieldIndex, metaProperty));
-        }
-
-        return result;
-    }
-
-    void deserialize(const QByteArray &array) {
-        qProtoDebug() << T::staticMetaObject.className() << "deserialize";
+    explicit ProtobufObject(QObject *parent = nullptr) {}
 
-        for (QByteArray::const_iterator it = array.begin(); it != array.end();) {
-            //Each iteration we expect iterator is setup to beginning of next chunk
-            int fieldNumber = NotUsedFieldIndex;
-            WireTypes wireType = UnknownWireType;
-            if (!decodeHeaderByte(*it, fieldNumber, wireType)) {
-                ++it;
-                qProtoCritical() << "Message received doesn't contains valid header byte. "
-                               "Trying next, but seems stream is broken";
-                continue;
-            }
-
-            auto propertyNumberIt = T::propertyOrdering.find(fieldNumber);
-            if (propertyNumberIt == std::end(T::propertyOrdering)) {
-                ++it;
-                qProtoCritical() << "Message received contains invalid field number. "
-                               "Trying next, but seems stream is broken";
-                continue;
-            }
-
-            int propertyIndex = propertyNumberIt->second;
-            QMetaProperty metaProperty = T::staticMetaObject.property(propertyIndex);
-
-            ++it;
-            deserializeProperty(wireType, metaProperty, it);
-        }
-    }
+    QByteArray serialize() const;
+    void deserialize(const QByteArray &array);
 
 protected:
-    static void registerSerializers(int metaTypeId, int listMetaTypeId) {
-        serializers[listMetaTypeId] = {Serializer(serializeComplexListType), Deserializer(deserializeComplexListType)};
-        serializers[metaTypeId] = {Serializer(serializeComplexType), Deserializer(deserializeComplexType)};
-    }
+    static void registerSerializers(int metaTypeId, int listMetaTypeId);
 
 private:
-
-    static QByteArray serializeComplexType(const QVariant &variantValue, int &/*outFieldIndex*/) {
-        T value = variantValue.value<T>();
-        return serializeLengthDelimited(value.serialize());
-    }
-
-    static void deserializeComplexType(ProtobufObjectPrivate *deserializer, QByteArray::const_iterator &it, QVariant &previous) {
-        T value;
-        value.deserialize(deserializer->deserializeLengthDelimited(it));
-        previous = QVariant::fromValue(value);
-    }
-
-    static QByteArray serializeComplexListType(const QVariant &listValue, int &outFieldIndex) {
-        QList<T> list = listValue.value<QList<T>>();
-        return serializeListType(list, outFieldIndex);
-    }
-
-    static void deserializeComplexListType(ProtobufObjectPrivate *deserializer, QByteArray::const_iterator &it, QVariant &previous) {
-        QList<T> previousList = previous.value<QList<T>>();
-        QVariant newMember = deserializer->deserializeListType<T>(it);
-        previousList.append(newMember.value<T>());
-        previous.setValue(previousList);
-    }
+    static QByteArray serializeComplexType(const QVariant &variantValue, int &outFieldIndex);
+    static void deserializeComplexType(QByteArray::const_iterator &it, QVariant &previous);
+    static QByteArray serializeComplexListType(const QVariant &listValue, int &outFieldIndex);
+    static void deserializeComplexListType(QByteArray::const_iterator &it, QVariant &previous);
 };
 
 }
+#include "protobufobject.inc"

+ 123 - 0
src/protobuf/protobufobject.inc

@@ -0,0 +1,123 @@
+/*
+ * MIT License
+ *
+ * Copyright (c) 2019 Alexey Edelev <semlanik@gmail.com>
+ *
+ * This file is part of qtprotobuf project https://git.semlanik.org/semlanik/qtprotobuf
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of this
+ * software and associated documentation files (the "Software"), to deal in the Software
+ * without restriction, including without limitation the rights to use, copy, modify,
+ * merge, publish, distribute, sublicense, and/or sell copies of the Software, and
+ * to permit persons to whom the Software is furnished to do so, subject to the following
+ * conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all copies
+ * or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
+ * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
+ * PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
+ * FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+ * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+
+#pragma once
+
+#include "protobufobject_p.h"
+
+#include <QMetaObject>
+#include <QMetaProperty>
+
+#include <qtprotobuftypes.h>
+#include <qtprotobuflogging.h>
+
+#define ASSERT_FIELD_NUMBER(X) Q_ASSERT_X(X < 128 && X > 0, T::staticMetaObject.className(), "fieldIndex is out of range")
+
+namespace qtprotobuf {
+
+template<typename T>
+QByteArray ProtobufObject<T>::serialize() const {
+    qProtoDebug() << T::staticMetaObject.className() << "serialize";
+
+    QByteArray result;
+    const QObject *instance = static_cast<const QObject *>(this);
+    for (auto field : T::propertyOrdering) {
+        int propertyIndex = field.second;
+        int fieldIndex = field.first;
+        ASSERT_FIELD_NUMBER(fieldIndex);
+        QMetaProperty metaProperty = T::staticMetaObject.property(propertyIndex);
+        const char *propertyName = metaProperty.name();
+        const QVariant &propertyValue = instance->property(propertyName);
+        result.append(ProtobufObjectPrivate::serializeValue(this, propertyValue, fieldIndex, metaProperty));
+    }
+
+    return result;
+}
+
+template<typename T>
+void ProtobufObject<T>::deserialize(const QByteArray &array) {
+    qProtoDebug() << T::staticMetaObject.className() << "deserialize";
+
+    for (QByteArray::const_iterator it = array.begin(); it != array.end();) {
+        //Each iteration we expect iterator is setup to beginning of next chunk
+        int fieldNumber = NotUsedFieldIndex;
+        WireTypes wireType = UnknownWireType;
+        if (!ProtobufObjectPrivate::decodeHeaderByte(*it, fieldNumber, wireType)) {
+            ++it;
+            qProtoCritical() << "Message received doesn't contains valid header byte. "
+                           "Trying next, but seems stream is broken";
+            continue;
+        }
+
+        auto propertyNumberIt = T::propertyOrdering.find(fieldNumber);
+        if (propertyNumberIt == std::end(T::propertyOrdering)) {
+            ++it;
+            qProtoCritical() << "Message received contains invalid field number. "
+                           "Trying next, but seems stream is broken";
+            continue;
+        }
+
+        int propertyIndex = propertyNumberIt->second;
+        QMetaProperty metaProperty = T::staticMetaObject.property(propertyIndex);
+
+        ++it;
+        ProtobufObjectPrivate::deserializeProperty(this, wireType, metaProperty, it);
+    }
+}
+
+template<typename T>
+void ProtobufObject<T>::registerSerializers(int metaTypeId, int listMetaTypeId) {
+    ProtobufObjectPrivate::serializers[listMetaTypeId] = {ProtobufObjectPrivate::Serializer(serializeComplexListType), ProtobufObjectPrivate::Deserializer(deserializeComplexListType)};
+    ProtobufObjectPrivate::serializers[metaTypeId] = {ProtobufObjectPrivate::Serializer(serializeComplexType), ProtobufObjectPrivate::Deserializer(deserializeComplexType)};
+}
+
+template<typename T>
+QByteArray ProtobufObject<T>::serializeComplexType(const QVariant &variantValue, int &/*outFieldIndex*/) {
+    T value = variantValue.value<T>();
+    return ProtobufObjectPrivate::serializeLengthDelimited(value.serialize());
+}
+
+template<typename T>
+void ProtobufObject<T>::deserializeComplexType(QByteArray::const_iterator &it, QVariant &previous) {
+    T value;
+    value.deserialize(ProtobufObjectPrivate::deserializeLengthDelimited(it));
+    previous = QVariant::fromValue(value);
+}
+
+template<typename T>
+QByteArray ProtobufObject<T>::serializeComplexListType(const QVariant &listValue, int &outFieldIndex) {
+    QList<T> list = listValue.value<QList<T>>();
+    return ProtobufObjectPrivate::serializeListType(list, outFieldIndex);
+}
+
+template<typename T>
+void ProtobufObject<T>::deserializeComplexListType(QByteArray::const_iterator &it, QVariant &previous) {
+    QList<T> previousList = previous.value<QList<T>>();
+    QVariant newMember = ProtobufObjectPrivate::deserializeListType<T>(it);
+    previousList.append(newMember.value<T>());
+    previous.setValue(previousList);
+}
+
+}

+ 92 - 117
src/protobuf/protobufobject.cpp → src/protobuf/protobufobject_p.cpp

@@ -23,61 +23,20 @@
  * DEALINGS IN THE SOFTWARE.
  */
 
-#include "protobufobject.h"
+#include "protobufobject_p.h"
 
 using namespace qtprotobuf;
 
 ProtobufObjectPrivate::SerializerRegistry ProtobufObjectPrivate::serializers = {};
 
-QByteArray ProtobufObjectPrivate::serializeValue(const QVariant &propertyValue, int fieldIndex, const QMetaProperty &metaProperty)
+QByteArray ProtobufObjectPrivate::serializeValue(const QObject* object, const QVariant &propertyValue, int fieldIndex, const QMetaProperty &metaProperty)
 {
-    QLatin1Literal typeName(metaProperty.typeName());
     QByteArray result;
     WireTypes type = UnknownWireType;
     qProtoDebug() << __func__ << "propertyValue" << propertyValue << "fieldIndex" << fieldIndex << "typeName"
-                  << typeName << static_cast<QMetaType::Type>(propertyValue.type());
+                  << metaProperty.typeName() << static_cast<QMetaType::Type>(propertyValue.type());
 
-    switch (static_cast<QMetaType::Type>(propertyValue.type())) {
-    case QMetaType::Long:
-    case QMetaType::Int:
-        type = Varint;
-        //FIXME:
-        //Serialize to int64_t bacause of issue in reference implementation
-        result.append(serializeVarint(propertyValue.value<int64_t>()));
-        if (0 == result.size()) {
-            fieldIndex = NotUsedFieldIndex;
-        }
-        break;
-    case QMetaType::LongLong:
-        type = Varint;
-        result.append(serializeVarint(propertyValue.value<int64_t>()));
-        if (0 == result.size()) {
-            fieldIndex = NotUsedFieldIndex;
-        }
-        break;
-    case QMetaType::ULong:
-    case QMetaType::UInt:
-        type = Varint;
-        result.append(serializeVarint(propertyValue.value<uint32_t>()));
-        if (0 == result.size()) {
-            fieldIndex = NotUsedFieldIndex;
-        }
-        break;
-    case QMetaType::ULongLong:
-        type = Varint;
-        result.append(serializeVarint(propertyValue.value<uint64_t>()));
-        if (0 == result.size()) {
-            fieldIndex = NotUsedFieldIndex;
-        }
-        break;
-    case QMetaType::Float:
-        type = Fixed32;
-        result.append(serializeFixed(propertyValue.toFloat()));
-        break;
-    case QMetaType::Double:
-        type = Fixed64;
-        result.append(serializeFixed(propertyValue.toDouble()));
-        break;
+    switch (metaProperty.userType()) {
     case QMetaType::QString:
         type = LengthDelimited;
         result.append(serializeLengthDelimited(propertyValue.toString()));
@@ -94,23 +53,18 @@ QByteArray ProtobufObjectPrivate::serializeValue(const QVariant &propertyValue,
         type = LengthDelimited;
         result.append(serializeListType(propertyValue.value<QByteArrayList>(), fieldIndex));
         break;
-    case QMetaType::User:
+    case QMetaType::Bool:
+        type = Varint;
+        result.append(serializeBasic(propertyValue.toUInt(), fieldIndex));
+        break;
+    default:
         if(metaProperty.isEnumType()) {
             type = Varint;
-            result.append(serializeVarint(propertyValue.toLongLong()));
+            result.append(serializeBasic(propertyValue.toLongLong(), fieldIndex));
         } else {
-            result.append(serializeUserType(propertyValue, fieldIndex, typeName, type));
+            result.append(serializeUserType(propertyValue, fieldIndex, type));
         }
         break;
-    case QMetaType::Bool:
-        type = Varint;
-        result.append(serializeVarint(propertyValue.toUInt()));
-        if (0 == result.size()) {
-            fieldIndex = NotUsedFieldIndex;
-        }
-        break;
-    default:
-        Q_ASSERT_X(false, staticMetaObject.className(), "Serialization of unknown type is impossible");
     }
     if (fieldIndex != NotUsedFieldIndex
             && type != UnknownWireType) {
@@ -119,7 +73,7 @@ QByteArray ProtobufObjectPrivate::serializeValue(const QVariant &propertyValue,
     return result;
 }
 
-QByteArray ProtobufObjectPrivate::serializeUserType(const QVariant &propertyValue, int &fieldIndex, const QLatin1Literal &typeName, WireTypes &type)
+QByteArray ProtobufObjectPrivate::serializeUserType(const QVariant &propertyValue, int &fieldIndex, WireTypes &type)
 {
 
     qProtoDebug() << __func__ << "propertyValue" << propertyValue << "fieldIndex" << fieldIndex;
@@ -133,29 +87,54 @@ QByteArray ProtobufObjectPrivate::serializeUserType(const QVariant &propertyValu
     }
 
     //Check if it's special type
+    if (userType == qMetaTypeId<float>()) {
+        type = Fixed32;
+        return serializeBasic(propertyValue.toFloat(), fieldIndex);
+    }
+    if (userType == qMetaTypeId<double>()) {
+        type = Fixed64;
+        return serializeBasic(propertyValue.toDouble(), fieldIndex);
+    }
+    if (userType == qMetaTypeId<int32>()) {
+        type = Varint;
+        //FIXME: Current implmentation serializes to int64_t bacause of issue in reference implementation
+        return serializeBasic(propertyValue.value<int64>(), fieldIndex);
+    }
+    if (userType == qMetaTypeId<int64>()) {
+        type = Varint;
+        return serializeBasic(propertyValue.value<int64>(), fieldIndex);
+    }
+    if (userType == qMetaTypeId<uint32>()) {
+        type = Varint;
+        return serializeBasic(propertyValue.value<uint32>(), fieldIndex);
+    }
+    if (userType == qMetaTypeId<uint64>()) {
+        type = Varint;
+        return serializeBasic(propertyValue.value<uint64>(), fieldIndex);
+    }
     if (userType == qMetaTypeId<sint32>()) {
         type = Varint;
-        return serializeVarintZigZag(propertyValue.value<sint32>());
+        return serializeBasic(propertyValue.value<sint32>(), fieldIndex);
     }
     if (userType == qMetaTypeId<sint64>()) {
         type = Varint;
-        return serializeVarintZigZag(propertyValue.value<sint64>());
+        return serializeBasic(propertyValue.value<sint64>(), fieldIndex);
     }
     if (userType == qMetaTypeId<fint32>()) {
         type = Fixed32;
-        return serializeFixed(propertyValue.value<fint32>());
+        return serializeBasic(propertyValue.value<fint32>(), fieldIndex);
     }
     if (userType == qMetaTypeId<fint64>()) {
         type = Fixed64;
-        return serializeFixed(propertyValue.value<fint64>());
+        return serializeBasic(propertyValue.value<fint64>(), fieldIndex);
     }
     if (userType == qMetaTypeId<sfint32>()) {
         type = Fixed32;
-        return serializeFixed(propertyValue.value<sfint32>());
+        return serializeBasic(propertyValue.value<sfint32>(), fieldIndex);
     }
     if (userType == qMetaTypeId<sfint64>()) {
         type = Fixed64;
-        return serializeFixed(propertyValue.value<sfint64>());
+        return serializeBasic(propertyValue.value<sfint64>(), fieldIndex);
     }
     if (userType == qMetaTypeId<fint32List>()) {
         return serializeListType(propertyValue.value<fint32List>(), fieldIndex);
@@ -176,10 +155,10 @@ QByteArray ProtobufObjectPrivate::serializeUserType(const QVariant &propertyValu
         return serializeListType(propertyValue.value<int64List>(), fieldIndex);
     }
     if (userType == qMetaTypeId<sint32List>()) {
-        return serializeListTypeZigZag(propertyValue.value<sint32List>(), fieldIndex);
+        return serializeListType(propertyValue.value<sint32List>(), fieldIndex);
     }
     if (userType == qMetaTypeId<sint64List>()) {
-        return serializeListTypeZigZag(propertyValue.value<sint64List>(), fieldIndex);
+        return serializeListType(propertyValue.value<sint64List>(), fieldIndex);
     }
     if (userType == qMetaTypeId<uint32List>()) {
         return serializeListType(propertyValue.value<uint32List>(), fieldIndex);
@@ -194,91 +173,87 @@ QByteArray ProtobufObjectPrivate::serializeUserType(const QVariant &propertyValu
         return serializeListType(propertyValue.value<DoubleList>(), fieldIndex);
     }
 
-    return serializers[userType].serializer(propertyValue, fieldIndex);
+    auto serializer = serializers[userType].serializer;
+    Q_ASSERT_X(serializer, "ProtobufObjectPrivate", "Serialization of unknown type is impossible");
+    return serializer(propertyValue, fieldIndex);
 }
 
-void ProtobufObjectPrivate::deserializeProperty(WireTypes wireType, const QMetaProperty &metaProperty, QByteArray::const_iterator &it)
+void ProtobufObjectPrivate::deserializeProperty(QObject *object, WireTypes wireType, const QMetaProperty &metaProperty, QByteArray::const_iterator &it)
 {
     QLatin1Literal typeName(metaProperty.typeName());
     qProtoDebug() << __func__ << " wireType: " << wireType << " metaProperty: " << typeName << "currentByte:" << QString::number((*it), 16);
     QVariant newPropertyValue;
-    int type = metaProperty.type();
-    switch (type) {
-    case QMetaType::UInt:
-        newPropertyValue = deserializeVarint<uint32>(it);
-        break;
-    case QMetaType::ULongLong:
-        newPropertyValue = deserializeVarint<uint64>(it);
-        break;
-    case QMetaType::Float:
-        newPropertyValue = deserializeFixed<float>(it);
-        break;
-    case QMetaType::Double:
-        newPropertyValue = deserializeFixed<double>(it);
-        break;
-    case QMetaType::Int:
-        newPropertyValue = deserializeVarint<int64>(it);
-        break;
-    case QMetaType::LongLong:
-        newPropertyValue = deserializeVarint<int64>(it);
-        break;
+    switch (metaProperty.userType()) {
     case QMetaType::QString:
         newPropertyValue = QString::fromUtf8(deserializeLengthDelimited(it));
         break;
     case QMetaType::QByteArray:
         newPropertyValue = deserializeLengthDelimited(it);
         break;
-    case QMetaType::User:
-        if (metaProperty.isEnumType()) {
-            newPropertyValue = deserializeVarint<int32>(it);
-        } else {
-            newPropertyValue = metaProperty.read(this);
-            deserializeUserType(metaProperty, it, newPropertyValue);
-        }
-        break;
     case QMetaType::QByteArrayList: {
-        QByteArrayList currentValue = metaProperty.read(this).value<QByteArrayList>();
+        QByteArrayList currentValue = metaProperty.read(object).value<QByteArrayList>();
         currentValue.append(deserializeLengthDelimited(it));
-        metaProperty.write(this, QVariant::fromValue<QByteArrayList>(currentValue));
+        metaProperty.write(object, QVariant::fromValue<QByteArrayList>(currentValue));
     }
         return;
     case QMetaType::QStringList: {
-        QStringList currentValue = metaProperty.read(this).value<QStringList>();
+        QStringList currentValue = metaProperty.read(object).value<QStringList>();
         currentValue.append(QString::fromUtf8(deserializeLengthDelimited(it)));
-        metaProperty.write(this, currentValue);
+        metaProperty.write(object, currentValue);
     }
         return;
     case QMetaType::Bool:
-        newPropertyValue = deserializeVarint<uint32>(it);
+        newPropertyValue = deserializeBasic<uint32>(it);
         break;
     default:
+        if (metaProperty.isEnumType()) {
+            newPropertyValue = deserializeBasic<int32>(it);
+        } else {
+            newPropertyValue = metaProperty.read(object);
+            deserializeUserType(metaProperty, it, newPropertyValue);
+        }
         break;
     }
-    metaProperty.write(this, newPropertyValue);
+    metaProperty.write(object, newPropertyValue);
 }
 
 void ProtobufObjectPrivate::deserializeUserType(const QMetaProperty &metaType, QByteArray::const_iterator& it, QVariant &newValue)
 {
     int userType = metaType.userType();
-    QLatin1Literal typeName(metaType.typeName());
-    qProtoDebug() << __func__ << "userType" << userType << "currentByte:" << QString::number((*it), 16);
+    qProtoDebug() << __func__ << "userType" << userType << "typeName" << metaType.typeName() << "currentByte:" << QString::number((*it), 16);
 
     auto serializerIt = serializers.find(userType);
     if (serializerIt != std::end(serializers)) {
-        (serializerIt->second).deserializer(this, it, newValue);
+        (serializerIt->second).deserializer(it, newValue);
         return;
     }
 
-    if (userType == qMetaTypeId<fint32>()) {
-        newValue = deserializeVarintZigZag<sint32>(it);
+    if (userType == qMetaTypeId<float>()) {
+        newValue = deserializeBasic<float>(it);
+    } else if (userType == qMetaTypeId<double>()) {
+        newValue = deserializeBasic<double>(it);
+    } else if (userType == qMetaTypeId<int32>()) {
+        newValue = deserializeBasic<int32>(it);
+    } else if (userType == qMetaTypeId<int64>()) {
+        newValue = deserializeBasic<int64>(it);
+    } else if (userType == qMetaTypeId<sint32>()) {
+        newValue = deserializeBasic<sint32>(it);
+    } else if (userType == qMetaTypeId<sint64>()) {
+        newValue = deserializeBasic<sint64>(it);
+    } else if (userType == qMetaTypeId<uint32>()) {
+        newValue = deserializeBasic<uint32>(it);
+    } else if (userType == qMetaTypeId<uint64>()) {
+        newValue = deserializeBasic<uint64>(it);
+    } else if (userType == qMetaTypeId<fint32>()) {
+        newValue = deserializeBasic<fint32>(it);
     } else if (userType == qMetaTypeId<fint32>()) {
-        newValue = deserializeFixed<fint32>(it);
+        newValue = deserializeBasic<fint32>(it);
     } else if (userType == qMetaTypeId<fint64>()) {
-        newValue = deserializeFixed<fint64>(it);
+        newValue = deserializeBasic<fint64>(it);
     } else if (userType == qMetaTypeId<sfint32>()) {
-        newValue = deserializeFixed<sfint32>(it);
+        newValue = deserializeBasic<sfint32>(it);
     } else if (userType == qMetaTypeId<sfint64>()) {
-        newValue = deserializeFixed<sfint64>(it);
+        newValue = deserializeBasic<sfint64>(it);
     } else if (userType == qMetaTypeId<fint32List>()) {
         newValue = deserializeListType<fint32>(it);
     } else if (userType == qMetaTypeId<fint64List>()) {
@@ -288,17 +263,17 @@ void ProtobufObjectPrivate::deserializeUserType(const QMetaProperty &metaType, Q
     } else if(userType == qMetaTypeId<sfint64List>()) {
         newValue = deserializeListType<sfint64>(it);
     } else if (userType == qMetaTypeId<int32List>()) {
-        newValue = deserializeVarintListType<int32>(it);
+        newValue = deserializeListType<int32>(it);
     } else if (userType == qMetaTypeId<int64List>()) {
-        newValue = deserializeVarintListType<int64>(it);
+        newValue = deserializeListType<int64>(it);
     } else if (userType == qMetaTypeId<sint32List>()) {
-        newValue = deserializeVarintListTypeZigZag<sint32>(it);
+        newValue = deserializeListType<sint32>(it);
     } else if (userType == qMetaTypeId<sint64List>()) {
-        newValue = deserializeVarintListTypeZigZag<sint64>(it);
+        newValue = deserializeListType<sint64>(it);
     } else if (userType == qMetaTypeId<uint32List>()) {
-        newValue = deserializeVarintListType<uint32>(it);
+        newValue = deserializeListType<uint32>(it);
     } else if (userType == qMetaTypeId<uint64List>()) {
-        newValue = deserializeVarintListType<uint64>(it);
+        newValue = deserializeListType<uint64>(it);
     } else if (userType == qMetaTypeId<FloatList>()) {
         newValue = deserializeListType<float>(it);
     } else if (userType == qMetaTypeId<DoubleList>()) {

+ 145 - 197
src/protobuf/protobufobject_p.h

@@ -33,24 +33,13 @@
 #include <unordered_map>
 #include <memory>
 #include <type_traits>
-#include <typeinfo>
 #include <functional>
 
 #include <qtprotobuftypes.h>
 #include <qtprotobuflogging.h>
 
-#define ASSERT_FIELD_NUMBER(X) Q_ASSERT_X(X < 128 && X > 0 && X != NotUsedFieldIndex, T::staticMetaObject.className(), "fieldIndex is out of range")
-
 namespace qtprotobuf {
 
-enum WireTypes {
-    UnknownWireType = -1,
-    Varint = 0,
-    Fixed64 = 1,
-    LengthDelimited = 2,
-    Fixed32 = 5
-};
-
 template<typename V>
 struct make_unsigned { typedef typename std::make_unsigned<V>::type type; };
 
@@ -60,13 +49,14 @@ struct make_unsigned<sint32> { typedef typename std::make_unsigned<decltype(sint
 template<>
 struct make_unsigned<sint64> { typedef typename std::make_unsigned<decltype(sint64::_t)>::type type; };
 
-constexpr int NotUsedFieldIndex = -1;
-
-class ProtobufObjectPrivate : public QObject
+class ProtobufObjectPrivate
 {
-protected:
+public:
+    static unsigned char encodeHeaderByte(int fieldIndex, WireTypes wireType);
+    static bool decodeHeaderByte(unsigned char typeByte, int &fieldIndex, WireTypes &wireType);
+
     using Serializer = std::function<QByteArray(const QVariant &, int &)>;
-    using Deserializer = std::function<void(ProtobufObjectPrivate *, QByteArray::const_iterator &, QVariant &)>;
+    using Deserializer = std::function<void(QByteArray::const_iterator &, QVariant &)>;
     struct SerializationHandlers {
         Serializer serializer;
         Deserializer deserializer;
@@ -75,81 +65,117 @@ protected:
     using SerializerRegistry = std::unordered_map<int/*metatypeid*/, SerializationHandlers>;
     static SerializerRegistry serializers;
 
-public:
-    explicit ProtobufObjectPrivate(QObject *parent = nullptr) : QObject(parent) {}
-
-    inline static unsigned char encodeHeaderByte(int fieldIndex, WireTypes wireType);
-    inline static bool decodeHeaderByte(unsigned char typeByte, int &fieldIndex, WireTypes &wireType);
+    ProtobufObjectPrivate() {}
 
-    static QByteArray serializeValue(const QVariant &propertyValue, int fieldIndex, const QMetaProperty &metaProperty);
-    static QByteArray serializeUserType(const QVariant &propertyValue, int &fieldIndex, const QLatin1Literal &typeName, WireTypes &type);
+    static QByteArray serializeValue(const QObject *object, const QVariant &propertyValue, int fieldIndex, const QMetaProperty &metaProperty);
+    static QByteArray serializeUserType(const QVariant &propertyValue, int &fieldIndex, WireTypes &type);
 
-    void deserializeProperty(WireTypes wireType, const QMetaProperty &metaProperty, QByteArray::const_iterator &it);
-    void deserializeUserType(const QMetaProperty &metaType, QByteArray::const_iterator &it, QVariant &newValue);
+    static void deserializeProperty(QObject *object, WireTypes wireType, const QMetaProperty &metaProperty, QByteArray::const_iterator &it);
+    static void deserializeUserType(const QMetaProperty &metaType, QByteArray::const_iterator &it, QVariant &newValue);
 
     //###########################################################################
     //                           Serialization helpers
     //###########################################################################
-    static QByteArray serializeLengthDelimited(const QString &data) {
-        qProtoDebug() << __func__ << "data.size" << data.size() << "data" << data;
-        return serializeLengthDelimited(data.toUtf8());
+    static void prependLengthDelimitedSize(QByteArray &serializedList)
+    {
+        int empty = NotUsedFieldIndex;
+        auto result = serializeBasic(static_cast<uint32_t>(serializedList.size()), empty);
+        //Zero case.
+        if (result.isEmpty()) {
+            result.append('\0');
+        }
+        serializedList.prepend(result);
     }
 
-    static QByteArray serializeLengthDelimited(const QByteArray &data) {
-        qProtoDebug() << __func__ << "data.size" << data.size() << "data" << data.toHex();
+    //----------------Serialize basic integral and floating point----------------
+    template <typename V,
+              typename std::enable_if_t<std::is_floating_point<V>::value
+                                        || std::is_same<V, fint32>::value
+                                        || std::is_same<V, fint64>::value
+                                        || std::is_same<V, sfint32>::value
+                                        || std::is_same<V, sfint64>::value, int> = 0>
+    static QByteArray serializeBasic(V value, int &) {
+        qProtoDebug() << __func__ << "value" << value;
 
-        //Varint serialize field size and apply result as starting point
-        QByteArray result = serializeVarintZero(static_cast<unsigned int>(data.size()));
-        result.append(data);
+        //Reserve required amount of bytes
+        QByteArray result(sizeof(V), '\0');
+        *(V*)(result.data()) = value;
         return result;
     }
 
-    template<typename V,
-             typename std::enable_if_t<std::is_same<sint32, V>::value
-                                       || std::is_same<sint64, V>::value, int> = 0>
-    static QByteArray serializeListTypeZigZag(const QList<V> &listValue, int &outFieldIndex) {
-        qProtoDebug() << __func__ << "listValue.count" << listValue.count() << "outFiledIndex" << outFieldIndex;
+    template <typename V,
+              typename std::enable_if_t<std::is_same<V, sint32>::value
+                                        || std::is_same<V, sint64>::value, int> = 0>
+    static QByteArray serializeBasic(V value, int &outFieldIndex) {
+        qProtoDebug() << __func__ << "value" << value;
+        using UV = typename qtprotobuf::make_unsigned<V>::type;
+        UV uValue = 0;
 
-        if (listValue.count() <= 0) {
-            outFieldIndex = NotUsedFieldIndex;
-            return QByteArray();
-        }
+        //Use ZigZag convertion first and apply unsigned variant next
+        value = (value << 1) ^ (value >> (sizeof(UV) * 8 - 1));
+        uValue = static_cast<UV>(value);
+        return serializeBasic(uValue, outFieldIndex);
+    }
 
-        QByteArray serializedList;
-        for (auto &value : listValue) {
-            serializedList.append(serializeVarintZigZag(value));
-        }
-        //If internal field type is not LengthDelimited, exact amount of fields to be specified
-        serializedList.prepend(serializeVarintZero(static_cast<unsigned int>(serializedList.size())));
-        return serializedList;
+    template <typename V,
+              typename std::enable_if_t<std::is_integral<V>::value
+                                        && std::is_signed<V>::value, int> = 0>
+    static QByteArray serializeBasic(V value, int &outFieldIndex) {
+        qProtoDebug() << __func__ << "value" << value;
+        using UV = typename qtprotobuf::make_unsigned<V>::type;
+        return serializeBasic(static_cast<UV>(value), outFieldIndex);
     }
 
-    template<typename V,
-             typename std::enable_if_t<std::is_same<V, int32>::value
-                                       || std::is_integral<V>::value, int> = 0>
-    static QByteArray serializeListType(const QList<V> &listValue, int &outFieldIndex) {
-        qProtoDebug() << __func__ << "listValue.count" << listValue.count() << "outFiledIndex" << outFieldIndex;
+    template <typename V,
+              typename std::enable_if_t<std::is_integral<V>::value
+                                        && std::is_unsigned<V>::value, int> = 0>
+    static QByteArray serializeBasic(V value, int &outFieldIndex) {
+        qProtoDebug() << __func__ << "value" << value;
 
-        if (listValue.count() <= 0) {
-            outFieldIndex = NotUsedFieldIndex;
-            return QByteArray();
+        QByteArray result;
+        //Reserve maximum required amount of bytes
+        result.reserve(sizeof(V));
+        while (value > 0) {
+            //Put first 7 bits to result buffer and mark as not last
+            result.append((value & 0x7F) | 0x80);
+            //Devide values to chunks of 7 bits, move to next chunk
+            value >>= 7;
         }
 
-        QByteArray serializedList;
-        for (auto &value : listValue) {
-            serializedList.append(serializeVarint<V>(value));
+        /* NOTE: Zero case aligned to reference cpp implementation. Where 0 ignored.
+         * if (result.isEmpty()) {
+         *     result.append('\0');
+         * }
+         */
+
+        //Mark last chunk as last or invalidate field in case if serialized result is empty
+        if (result.size() == 0) {
+            outFieldIndex = NotUsedFieldIndex;
+        } else {
+            result.data()[result.size() - 1] &= ~0x80;
         }
-        //If internal field type is not LengthDelimited, exact amount of fields to be specified
-        serializedList.prepend(serializeVarintZero(static_cast<unsigned int>(serializedList.size())));
-        return serializedList;
+        return result;
     }
 
+    //----------------Serialize length delimited bytes and strings---------------
+    static QByteArray serializeLengthDelimited(const QString &data) {
+        qProtoDebug() << __func__ << "data.size" << data.size() << "data" << data;
+        return serializeLengthDelimited(data.toUtf8());
+    }
+
+    static QByteArray serializeLengthDelimited(const QByteArray &data) {
+        qProtoDebug() << __func__ << "data.size" << data.size() << "data" << data.toHex();
+        QByteArray result(data);
+        //Varint serialize field size and apply result as starting point
+        prependLengthDelimitedSize(result);
+        return result;
+    }
+
+    //------------------------Serialize lists of any type------------------------
     template<typename V,
-             typename std::enable_if_t<std::is_floating_point<V>::value
-                                       || std::is_same<V, fint32>::value
-                                       || std::is_same<V, fint64>::value
-                                       || std::is_same<V, sfint32>::value
-                                       || std::is_same<V, sfint64>::value, int> = 0>
+             typename std::enable_if_t<!(std::is_same<V, QString>::value
+                                       || std::is_same<V, QByteArray>::value
+                                       || std::is_base_of<QObject, V>::value), int> = 0>
     static QByteArray serializeListType(const QList<V> &listValue, int &outFieldIndex) {
         qProtoDebug() << __func__ << "listValue.count" << listValue.count() << "outFiledIndex" << outFieldIndex;
 
@@ -158,12 +184,13 @@ public:
             return QByteArray();
         }
 
+        int empty = NotUsedFieldIndex;
         QByteArray serializedList;
         for (auto &value : listValue) {
-            serializedList.append(serializeFixed(value));
+            serializedList.append(serializeBasic<V>(value, empty));
         }
         //If internal field type is not LengthDelimited, exact amount of fields to be specified
-        serializedList.prepend(serializeVarintZero(static_cast<unsigned int>(serializedList.size())));
+        prependLengthDelimitedSize(serializedList);
         return serializedList;
     }
 
@@ -189,7 +216,7 @@ public:
     }
 
     template<typename V,
-             typename std::enable_if_t<std::is_base_of<ProtobufObjectPrivate, V>::value, int> = 0>
+             typename std::enable_if_t<std::is_base_of<QObject, V>::value, int> = 0>
     static QByteArray serializeListType(const QList<V> &listValue, int &outFieldIndex) {
         qProtoDebug() << __func__ << "listValue.count" << listValue.count() << "outFiledIndex" << outFieldIndex;
 
@@ -210,92 +237,35 @@ public:
         return serializedList;
     }
 
+    //###########################################################################
+    //                           Deserialization helpers
+    //###########################################################################
     template <typename V,
               typename std::enable_if_t<std::is_floating_point<V>::value
-                                        || std::is_same<V, fint32>::value
-                                        || std::is_same<V, fint64>::value
                                         || std::is_same<V, sfint32>::value
-                                        || std::is_same<V, sfint64>::value, int> = 0>
-    static QByteArray serializeFixed(V value) {
-        qProtoDebug() << __func__ << "value" << value;
-
-        //Reserve required amount of bytes
-        QByteArray result(sizeof(V), '\0');
-        *(V*)(result.data()) = value;
-        return result;
-    }
-
-    template <typename V, typename UV = typename qtprotobuf::make_unsigned<V>::type,
-              typename std::enable_if_t<std::is_signed<V>::value, int> = 0>
-    static QByteArray serializeVarint(V value) {
-        qProtoDebug() << __func__ << "value" << value;
-
-        return serializeVarint(static_cast<UV>(value));
-    }
-
-    template <typename V, typename UV = typename qtprotobuf::make_unsigned<V>::type,
-              typename std::enable_if_t<std::is_same<V, sint32>::value
-                                        || std::is_same<V, sint64>::value, int> = 0>
-    static QByteArray serializeVarintZigZag(V value) {
-        qProtoDebug() << __func__ << "value" << value;
-
-        UV uValue = 0;
-
-        //Use ZigZag convertion first and apply unsigned variant next
-        value = (value << 1) ^ (value >> (sizeof(UV) * 8 - 1));
-        uValue = static_cast<UV>(value);
-        return serializeVarint(uValue);
-    }
-
-    template <typename V,
-              typename std::enable_if_t<std::is_unsigned<V>::value, int> = 0>
-    static QByteArray serializeVarint(V value) {
-        qProtoDebug() << __func__ << "value" << value;
-
-        QByteArray result;
-        //Reserve maximum required amount of bytes
-        result.reserve(sizeof(V));
-        while (value > 0) {
-            //Put first 7 bits to result buffer and mark as not last
-            result.append((value & 0x7F) | 0x80);
-            //Devide values to chunks of 7 bits, move to next chunk
-            value >>= 7;
-        }
-
-        //TODO: Zero case.
-        //Aligned to reference cpp implementation. Where 0 ignored.
-        //if (result.isEmpty()) {
-        //    result.append('\0');
-        //}
-
-        //Mark last chunk as last
-        result.data()[result.size() - 1] &= ~0x80;
-        return result;
+                                        || std::is_same<V, sfint64>::value
+                                        || std::is_same<V, fint32>::value
+                                        || std::is_same<V, fint64>::value, int> = 0>
+    static uint32 getRepeatedFieldCount(QByteArray::const_iterator &it) {
+        return deserializeBasic<uint32>(it).value<uint32>() / sizeof(V);
     }
 
     template <typename V,
-              typename std::enable_if_t<std::is_unsigned<V>::value, int> = 0>
-    static QByteArray serializeVarintZero(V value) {
-        qProtoDebug() << __func__ << "value" << value;
-
-        QByteArray result = serializeVarint(value);
-        //Zero case.
-        if (result.isEmpty()) {
-            result.append('\0');
-        }
-        return result;
+              typename std::enable_if_t<std::is_integral<V>::value
+                                        || std::is_same<V, sint32>::value
+                                        || std::is_same<V, sint64>::value, int> = 0>
+    static uint32 getRepeatedFieldCount(QByteArray::const_iterator &it) {
+        return deserializeBasic<uint32>(it).value<uint32>();
     }
 
-    //###########################################################################
-    //                           Deserialization helpers
-    //###########################################################################
+    //---------------Deserialize basic integral and floating point---------------
     template <typename V,
               typename std::enable_if_t<std::is_floating_point<V>::value
                                         || std::is_same<V, fint32>::value
                                         || std::is_same<V, fint64>::value
                                         || std::is_same<V, sfint32>::value
                                         || std::is_same<V, sfint64>::value, int> = 0>
-    QVariant deserializeFixed(QByteArray::const_iterator &it) {
+    static QVariant deserializeBasic(QByteArray::const_iterator &it) {
         qProtoDebug() << __func__ << "currentByte:" << QString::number((*it), 16);
 
         QVariant newPropertyValue(QVariant::fromValue(*(V*)it));
@@ -304,36 +274,40 @@ public:
     }
 
     template <typename V,
-              typename std::enable_if_t<std::is_unsigned<V>::value, int> = 0>
-    QVariant deserializeVarint(QByteArray::const_iterator &it) {
+              typename std::enable_if_t<std::is_integral<V>::value
+                                        && std::is_unsigned<V>::value, int> = 0>
+    static QVariant deserializeBasic(QByteArray::const_iterator &it) {
         qProtoDebug() << __func__ << "currentByte:" << QString::number((*it), 16);
 
         return QVariant::fromValue(deserializeVarintCommon<V>(it));
     }
 
-    template <typename V, typename UV = typename qtprotobuf::make_unsigned<V>::type,
+    template <typename V,
               typename std::enable_if_t<std::is_same<sint32, V>::value
                                         || std::is_same<sint64, V>::value,int> = 0>
-    QVariant deserializeVarintZigZag(QByteArray::const_iterator &it) {
+    static QVariant deserializeBasic(QByteArray::const_iterator &it) {
         qProtoDebug() << __func__ << "currentByte:" << QString::number((*it), 16);
-
+        using  UV = typename qtprotobuf::make_unsigned<V>::type;
         UV unsignedValue = deserializeVarintCommon<UV>(it);
         V value = (unsignedValue >> 1) ^ (-(unsignedValue & 1));
         return QVariant::fromValue<V>(value);
     }
 
-    template <typename V, typename UV = typename qtprotobuf::make_unsigned<V>::type,
-              typename std::enable_if_t<std::is_signed<V>::value, int> = 0>
-    QVariant deserializeVarint(QByteArray::const_iterator &it) {
+    template <typename V,
+              typename std::enable_if_t<std::is_integral<V>::value
+                                        && std::is_signed<V>::value, int> = 0>
+    static QVariant deserializeBasic(QByteArray::const_iterator &it) {
         qProtoDebug() << __func__ << "currentByte:" << QString::number((*it), 16);
-
+        using  UV = typename qtprotobuf::make_unsigned<V>::type;
         UV unsignedValue = deserializeVarintCommon<UV>(it);
         V value = static_cast<V>(unsignedValue);
         return QVariant::fromValue(value);
     }
 
-    template <typename V>
-    V deserializeVarintCommon(QByteArray::const_iterator &it) {
+    template <typename V,
+              typename std::enable_if_t<std::is_integral<V>::value
+                                        && std::is_unsigned<V>::value, int> = 0>
+    static V deserializeVarintCommon(QByteArray::const_iterator &it) {
         qProtoDebug() << __func__ << "currentByte:" << QString::number((*it), 16);
 
         V value = 0;
@@ -351,92 +325,66 @@ public:
         return value;
     }
 
-    QByteArray deserializeLengthDelimited(QByteArray::const_iterator &it) {
+    //---------------Deserialize length delimited bytes and strings--------------
+    static QByteArray deserializeLengthDelimited(QByteArray::const_iterator &it) {
         qProtoDebug() << __func__ << "currentByte:" << QString::number((*it), 16);
 
-        unsigned int length = deserializeVarint<unsigned int>(it).toUInt();
+        unsigned int length = deserializeBasic<unsigned int>(it).toUInt();
         QByteArray result(it, length);
         it += length;
         return result;
     }
 
+    //-----------------------Deserialize lists of any type-----------------------
     template <typename V,
               typename std::enable_if_t<std::is_same<V, QString>::value
                                         || std::is_same<V, QByteArray>::value, int> = 0>
-    QByteArray deserializeListType(QByteArray::const_iterator &it) {
+    static QByteArray deserializeListType(QByteArray::const_iterator &it) {
         qProtoDebug() << __func__ << "currentByte:" << QString::number((*it), 16);
 
         return deserializeLengthDelimited(it);
     }
 
     template <typename V,
-              typename std::enable_if_t<std::is_base_of<ProtobufObjectPrivate, V>::value, int> = 0>
-    QVariant deserializeListType(QByteArray::const_iterator &it) {
+              typename std::enable_if_t<std::is_base_of<QObject, V>::value, int> = 0>
+    static QVariant deserializeListType(QByteArray::const_iterator &it) {
         qProtoDebug() << __func__ << "currentByte:" << QString::number((*it), 16);
         QVariant newValue;
-        serializers[qMetaTypeId<V>()].deserializer(this, it, newValue);
+        serializers[qMetaTypeId<V>()].deserializer(it, newValue);
         return newValue;
     }
 
     template <typename V,
-              typename std::enable_if_t<std::is_floating_point<V>::value
-                                        || std::is_same<V, sfint32>::value
-                                        || std::is_same<V, sfint64>::value
-                                        || std::is_same<V, fint32>::value
-                                        || std::is_same<V, fint64>::value, int> = 0>
-    QVariant deserializeListType(QByteArray::const_iterator &it) {
+              typename std::enable_if_t<!(std::is_same<V, QString>::value
+                                        || std::is_same<V, QByteArray>::value
+                                        || std::is_base_of<QObject, V>::value), int> = 0>
+    static QVariant deserializeListType(QByteArray::const_iterator &it) {
         qProtoDebug() << __func__ << "currentByte:" << QString::number((*it), 16);
 
         QList<V> out;
-        unsigned int count = deserializeVarint<unsigned int>(it).toUInt() / sizeof(V);
-        for (unsigned int i = 0; i < count; i++) {
-            QVariant variant = deserializeFixed<V>(it);
-            out.append(variant.value<V>());
-        }
-        return QVariant::fromValue(out);
-    }
-
-    template <typename V>
-    QVariant deserializeVarintListType(QByteArray::const_iterator &it) {
-        qProtoDebug() << __func__ << "currentByte:" << QString::number((*it), 16);
-
-        QList<V> out;
-        unsigned int count = deserializeVarint<unsigned int>(it).toUInt();
+        unsigned int count = deserializeBasic<uint32>(it).toUInt();
         QByteArray::const_iterator lastVarint = it + count;
         while (it != lastVarint) {
-            QVariant variant = deserializeVarint<V>(it);
-            out.append(variant.value<V>());
-        }
-        return QVariant::fromValue(out);
-    }
-
-    template <typename V>
-    QVariant deserializeVarintListTypeZigZag(QByteArray::const_iterator &it) {
-        qProtoDebug() << __func__ << "currentByte:" << QString::number((*it), 16);
-
-        QList<V> out;
-        unsigned int count = deserializeVarint<unsigned int>(it).toUInt();
-        QByteArray::const_iterator lastVarint = it + count;
-        while (it != lastVarint) {
-            QVariant variant = deserializeVarintZigZag<V>(it);
+            QVariant variant = deserializeBasic<V>(it);
             out.append(variant.value<V>());
         }
         return QVariant::fromValue(out);
     }
 };
 
+
 /*  Header byte
  *  bits    | 7  6  5  4  3 | 2  1  0
  *  -----------------------------------
  *  meaning |  Field index  |  Type
  */
-unsigned char ProtobufObjectPrivate::encodeHeaderByte(int fieldIndex, WireTypes wireType)
+inline unsigned char ProtobufObjectPrivate::encodeHeaderByte(int fieldIndex, WireTypes wireType)
 {
     unsigned char header = (fieldIndex << 3) | wireType;
     return static_cast<char>(header);
 }
 
-bool ProtobufObjectPrivate::decodeHeaderByte(unsigned char typeByte, int &fieldIndex, WireTypes &wireType)
+inline bool ProtobufObjectPrivate::decodeHeaderByte(unsigned char typeByte, int &fieldIndex, WireTypes &wireType)
 {
     wireType = static_cast<WireTypes>(typeByte & 0x07);
     fieldIndex = typeByte >> 3;

+ 12 - 1
src/protobuf/qtprotobuftypes.h

@@ -29,6 +29,18 @@
 #include <QList>
 #include <QMetaType>
 
+namespace qtprotobuf {
+
+enum WireTypes {
+    UnknownWireType = -1,
+    Varint = 0,
+    Fixed64 = 1,
+    LengthDelimited = 2,
+    Fixed32 = 5
+};
+
+constexpr int NotUsedFieldIndex = -1;
+
 template<typename T, int = 0>
 struct transparent {
     transparent(T t = T()) : _t(t){}
@@ -37,7 +49,6 @@ struct transparent {
     operator T() const { return _t; }
 };
 
-namespace qtprotobuf {
 using int32 = int32_t;
 using int64 = int64_t;
 using uint32 = uint32_t;

+ 1 - 2
tests/serializationtest.cpp

@@ -739,7 +739,7 @@ TEST_F(SerializationTest, UInt64MessageSerializeTest)
     ASSERT_EQ(result.at(2), '\x80');
     ASSERT_EQ(result.at(3), '\x04');
 
-    test.setTestFieldInt((qulonglong)UINT32_MAX + 1);
+    test.setTestFieldInt(((uint64_t)UINT32_MAX) + 1);
     result = test.serialize();
     ASSERT_EQ(result.size(), 6);
     ASSERT_EQ(result.at(0), 0x08);
@@ -1486,7 +1486,6 @@ TEST_F(SerializationTest, RepeatedFixedIntMessageTest)
     QByteArray result = test.serialize();
     //qDebug() << "result " << result.toHex();
     ASSERT_TRUE(result == QByteArray::fromHex("0a180100000041010000cf010100ab0ebc000300000003000000"));
-
     test.setTestRepeatedInt(fint32List());
     result = test.serialize();
     ASSERT_TRUE(result.isEmpty());