Browse Source

Implement complex lists deserialzer

- Implement complex lists deserialzer
- Fix complex list serialization
- Add and update related tests
Alexey Edelev 6 years ago
parent
commit
52e12d712e
4 changed files with 75 additions and 22 deletions
  1. 1 1
      src/lib/protobufobject.cpp
  2. 52 18
      src/lib/protobufobject.h
  3. 19 0
      tests/deserializationtest.cpp
  4. 3 3
      tests/serializationtest.cpp

+ 1 - 1
src/lib/protobufobject.cpp

@@ -27,4 +27,4 @@
 
 using namespace qtprotobuf;
 
-ProtobufObjectPrivate::ListSerializerRegistry ProtobufObjectPrivate::listSerializers;
+ProtobufObjectPrivate::SerializerRegistry ProtobufObjectPrivate::serializers = {};

+ 52 - 18
src/lib/protobufobject.h

@@ -56,8 +56,14 @@ constexpr int NotUsedFieldIndex = -1;
 class ProtobufObjectPrivate : public QObject {
 public:
     using ListSerializer = std::function<QByteArray(const ProtobufObjectPrivate *, const QVariant &, int &)>;
-    using ListSerializerRegistry = std::unordered_map<int/*metatypeid*/, ListSerializer>;
-    static ListSerializerRegistry listSerializers;
+    using ListDeserializer = std::function<void(ProtobufObjectPrivate *, QByteArray::const_iterator &, QVariant &)>;
+    struct SerializationHandlers {
+        ListSerializer serializer;
+        ListDeserializer deserializer;
+    };
+
+    using SerializerRegistry = std::unordered_map<int/*metatypeid*/, SerializationHandlers>;
+    static SerializerRegistry serializers;
 
     explicit ProtobufObjectPrivate(QObject *parent = nullptr) : QObject(parent) {}
 
@@ -155,9 +161,9 @@ public:
         qProtoDebug() << __func__ << "propertyValue" << propertyValue << "fieldIndex" << fieldIndex;
         int userType = propertyValue.userType();
 
-        auto it = listSerializers.find(userType);
-        if (it != std::end(listSerializers)) {
-            return (it->second)(this, propertyValue, fieldIndex);
+        auto it = serializers.find(userType);
+        if (it != std::end(serializers)) {
+            return (it->second).serializer(this, propertyValue, fieldIndex);
         }
 
         if (userType == qMetaTypeId<IntList>()) {
@@ -226,10 +232,13 @@ public:
 
         QByteArray serializedList;
         for(auto& value : listValue) {
-            serializedList.append(value.serialize());
+            QByteArray serializedValue = serializeLengthDelimited(value.serialize());
+            serializedValue.prepend(encodeHeaderByte(outFieldIndex, LengthDelimited));
+            serializedList.append(serializedValue);
         }
 
-        serializedList.prepend(serializeVarint(static_cast<unsigned int>(serializedList.size())));
+        outFieldIndex = NotUsedFieldIndex;
+
         return serializedList;
     }
 
@@ -285,7 +294,7 @@ public:
 //####################################################
     void deserializeProperty(WireTypes wireType, const QMetaProperty &metaProperty, QByteArray::const_iterator &it)
     {
-        qProtoDebug() << __func__ << " wireType: " << wireType << " metaProperty: " << metaProperty.typeName();
+        qProtoDebug() << __func__ << " wireType: " << wireType << " metaProperty: " << metaProperty.typeName() << "currentByte:" << QString::number((*it),16);
         QVariant newPropertyValue;
         int type = metaProperty.type();
         switch(type) {
@@ -319,6 +328,7 @@ public:
             newPropertyValue = deserializeLengthDelimited(it);
             break;
         case QMetaType::User:
+            newPropertyValue = metaProperty.read(this);
             deserializeUserType(metaProperty.userType(), it, newPropertyValue);
             break;
         case QMetaType::QByteArrayList: {
@@ -344,7 +354,7 @@ public:
                                         || std::is_same<V, unsigned int>::value
                                         || std::is_same<V, qulonglong>::value, int> = 0>
     QVariant deserializeFixed(QByteArray::const_iterator &it) {
-        qProtoDebug() << __func__;
+        qProtoDebug() << __func__ << "currentByte:" << QString::number((*it),16);
         QVariant newPropertyValue(QVariant::fromValue(*(V*)it));
         it += sizeof(V);
         return newPropertyValue;
@@ -353,14 +363,14 @@ public:
     template <typename V,
               typename std::enable_if_t<std::is_unsigned<V>::value, int> = 0>
     QVariant deserializeVarint(QByteArray::const_iterator &it) {
-        qProtoDebug() << __func__;
+        qProtoDebug() << __func__ << "currentByte:" << QString::number((*it),16);
         return QVariant::fromValue(deserializeVarintCommon<V>(it));
     }
 
     template <typename V,
               typename std::enable_if_t<std::is_signed<V>::value, int> = 0>
     QVariant deserializeVarint(QByteArray::const_iterator &it) {
-        qProtoDebug() << __func__;
+        qProtoDebug() << __func__ << "currentByte:" << QString::number((*it),16);
         using UV = typename std::make_unsigned<V>::type;
         UV unsignedValue = deserializeVarintCommon<UV>(it);
         V value = (unsignedValue >> 1) ^ (-(unsignedValue & 1));
@@ -370,7 +380,7 @@ public:
 
     template <typename V>
     V deserializeVarintCommon(QByteArray::const_iterator &it) {
-        qProtoDebug() << __func__;
+        qProtoDebug() << __func__ << "currentByte:" << QString::number((*it),16);
         V value = 0;
         int k = 0;
         while((*it) & 0x80) {
@@ -384,7 +394,7 @@ public:
     }
 
     QByteArray deserializeLengthDelimited(QByteArray::const_iterator &it) {
-        qProtoDebug() << __func__;
+        qProtoDebug() << __func__ << "currentByte:" << QString::number((*it),16);
         unsigned int length = deserializeVarint<unsigned int>(it).toUInt();
         QByteArray result(it, length);
         it += length;
@@ -393,7 +403,14 @@ public:
 
     void deserializeUserType(int userType, QByteArray::const_iterator& it, QVariant &newValue)
     {
-        qProtoDebug() << __func__ << "userType" << userType;
+        qProtoDebug() << __func__ << "userType" << userType << "currentByte:" << QString::number((*it),16);
+
+        auto serializerIt = serializers.find(userType);
+        if (serializerIt != std::end(serializers)) {
+            (serializerIt->second).deserializer(this, it, newValue);
+            return;
+        }
+
         if (userType == qMetaTypeId<IntList>()) {
             newValue = deserializeVarintListType<int>(it);
         } else if(userType == qMetaTypeId<FloatList>()) {
@@ -411,16 +428,26 @@ public:
               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) {
-        qProtoDebug() << __func__;
+        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) {
+        qProtoDebug() << __func__ << "currentByte:" << QString::number((*it),16);
+        int metaTypeId = qMetaTypeId<V>();
+        QVariant variant;
+        deserializeUserType(metaTypeId, it, variant);
+        return variant;
+    }
+
     template <typename V,
               typename std::enable_if_t<std::is_floating_point<V>::value
                                         || std::is_same<V, unsigned int>::value
                                         || std::is_same<V, qulonglong>::value, int> = 0>
     QVariant deserializeListType(QByteArray::const_iterator& it) {
-        qProtoDebug() << __func__;
+        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++) {
@@ -433,7 +460,7 @@ public:
     template <typename V,
               typename std::enable_if_t<std::is_same<V, int>::value, int> = 0>
     QVariant deserializeVarintListType(QByteArray::const_iterator& it) {
-        qProtoDebug() << __func__;
+        qProtoDebug() << __func__ << "currentByte:" << QString::number((*it),16);
         QList<V> out;
         unsigned int count = deserializeVarint<unsigned int>(it).toUInt();
         QByteArray::const_iterator lastVarint = it + count;
@@ -454,7 +481,7 @@ class ProtobufObject : public ProtobufObjectPrivate
 {
 protected:
     static void registerSerializers(int metaTypeId, int listMetaTypeId) {
-        listSerializers[listMetaTypeId] = ListSerializer(serializeComplexListType);
+        serializers[listMetaTypeId] = {ListSerializer(serializeComplexListType), ListDeserializer(deserializeComplexListType)};
     }
 
     QByteArray serializePrivate() const override {
@@ -499,6 +526,13 @@ public:
         return serializer->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);
+    }
+
     void deserialize(const QByteArray &array) {
         qProtoDebug() << T::staticMetaObject.className() << "deserialize";
         //T *instance = dynamic_cast<T *>(this);

+ 19 - 0
tests/deserializationtest.cpp

@@ -37,6 +37,7 @@
 #include "repeateddoublemessage.h"
 #include "repeatedfloatmessage.h"
 #include "repeatedintmessage.h"
+#include "repeatedcomplexmessage.h"
 
 using namespace qtprotobufnamespace::tests;
 using namespace qtprotobuf::tests;
@@ -300,3 +301,21 @@ TEST_F(DeserializationTest, RepeatedIntMessageTest)
     ASSERT_EQ(6, test.testRepeatedInt().count());
     ASSERT_TRUE(test.testRepeatedInt() == IntList({1, 400, 3, 4, 5, 6}));
 }
+
+TEST_F(DeserializationTest, RepeatedComplexMessageTest)
+{
+    RepeatedComplexMessage test;
+    test.deserialize(QByteArray::fromHex("0a0c0832120832067177657274790a0c0832120832067177657274790a0c083212083206717765727479"));
+    ASSERT_EQ(3, test.testRepeatedComplex().count());
+    ASSERT_EQ(25, test.testRepeatedComplex().at(0).testFieldInt());
+    ASSERT_TRUE(test.testRepeatedComplex().at(0).testComplexField().testFieldString() == QString("qwerty"));
+    ASSERT_EQ(25, test.testRepeatedComplex().at(1).testFieldInt());
+    ASSERT_TRUE(test.testRepeatedComplex().at(1).testComplexField().testFieldString() == QString("qwerty"));
+    ASSERT_EQ(25, test.testRepeatedComplex().at(2).testFieldInt());
+    ASSERT_TRUE(test.testRepeatedComplex().at(2).testComplexField().testFieldString() == QString("qwerty"));
+
+    test.deserialize(QByteArray::fromHex("0a0c120832067177657274790832"));
+    ASSERT_LT(0, test.testRepeatedComplex().count());
+    ASSERT_EQ(25, test.testRepeatedComplex().at(0).testFieldInt());
+    ASSERT_TRUE(test.testRepeatedComplex().at(0).testComplexField().testFieldString() == QString("qwerty"));
+}

+ 3 - 3
tests/serializationtest.cpp

@@ -537,12 +537,12 @@ TEST_F(SerializationTest, RepeatedComplexMessageTest)
     msg.setTestFieldInt(25);
     msg.setTestComplexField(stringMsg);
     RepeatedComplexMessage test;
-    test.setTestRepeatedComplex({msg});
+    test.setTestRepeatedComplex({msg, msg, msg});
     qDebug() << test.testRepeatedComplex().count();
     QByteArray result = test.serialize();
     qDebug() << "result " << result.toHex();
-    ASSERT_TRUE(result == QByteArray::fromHex("0a0c083212083206717765727479")
-                || result == QByteArray::fromHex("0a0c120832067177657274790832"));
+    ASSERT_TRUE(result == QByteArray::fromHex("0a0c0832120832067177657274790a0c0832120832067177657274790a0c083212083206717765727479")
+                || result == QByteArray::fromHex("0a0c1208320671776572747908320a0c1208320671776572747908320a0c120832067177657274790832"));
 
     test.setTestRepeatedComplex({});
     result = test.serialize();