Browse Source

Implement deserialization for integer types

- Implement vaid Varint deserialization for int/sint/uint
- Implement and update tests
Alexey Edelev 6 years ago
parent
commit
4a91914954

+ 5 - 0
src/generator/classgeneratorbase.cpp

@@ -91,6 +91,11 @@ void ClassGeneratorBase::printPublic()
     mPrinter.Print(Templates::PublicBlockTemplate);
 }
 
+void ClassGeneratorBase::printPrivate()
+{
+    mPrinter.Print(Templates::PrivateBlockTemplate);
+}
+
 void ClassGeneratorBase::printMetaTypeDeclaration()
 {
     std::string namespaces;

+ 1 - 0
src/generator/classgeneratorbase.h

@@ -59,6 +59,7 @@ protected:
     void printNamespaces(const std::vector<std::string> &namespaces);
     void printClassDeclaration();
     void printPublic();
+    void printPrivate();
     void encloseClass();
     void printMetaTypeDeclaration();
     void encloseNamespaces();

+ 4 - 1
src/generator/protobufclassgenerator.cpp

@@ -351,7 +351,9 @@ void ProtobufClassGenerator::printProperties()
 
 void ProtobufClassGenerator::printRegisterTypes()
 {
+    Indent();
     mPrinter.Print(Templates::ComplexTypeRegistrationMethodTemplate);
+    Outdent();
 }
 
 void ProtobufClassGenerator::printListType()
@@ -396,10 +398,11 @@ void ProtobufClassGenerator::run()
     printIncludes(extractModels());
     printNamespaces();
     printClassDeclaration();
-    printRegisterTypes();
     printProperties();
     printPublic();
+    printRegisterTypes();
     printFieldsOrderingDefinition();
+    printPrivate();
     printClassMembers();
     encloseClass();
     printListType();

+ 2 - 1
src/generator/templates.cpp

@@ -41,7 +41,7 @@ const char *Templates::ListModelsIncludeTemplate = "#include <QList>\n";
 const char *Templates::GlobalEnumIncludeTemplate = "#include <globalenums.h>\n";
 
 const char *Templates::UsingQtProtobufNamespaceTemplate = "\nusing namespace qtprotobuf;\n";
-const char *Templates::ComplexTypeRegistrationMethodTemplate = "\n    static void registerTypes();\n";
+const char *Templates::ComplexTypeRegistrationMethodTemplate = "static void registerTypes();\n";
 const char *Templates::ComplexTypeRegistrationTemplate = "void $classname$::registerTypes()\n{\n"
                                                          "    static bool registationDone = false;\n"
                                                          "    if (!registationDone) {\n\n"
@@ -68,6 +68,7 @@ const char *Templates::PropertyTemplate = "Q_PROPERTY($type$ $property_name$ REA
 const char *Templates::MessagePropertyTemplate = "Q_PROPERTY($type$ $property_name$ READ $property_name$ WRITE set$property_name_cap$ NOTIFY $property_name$Changed)\n";
 const char *Templates::MemberTemplate = "$type$ m_$property_name$;\n";
 const char *Templates::PublicBlockTemplate = "\npublic:\n";
+const char *Templates::PrivateBlockTemplate = "\nprivate:\n";
 const char *Templates::EnumDefinitionTemplate = "enum $enum$ {\n";
 const char *Templates::EnumFieldTemplate = "$enumvalue$ = $value$,\n";
 const char *Templates::ConstructorTemplate = "$classname$(QObject *parent = nullptr) : ProtobufObject(parent)\n";

+ 1 - 0
src/generator/templates.h

@@ -52,6 +52,7 @@ public:
     static const char *MessagePropertyTemplate;
     static const char *MemberTemplate;
     static const char *PublicBlockTemplate;
+    static const char *PrivateBlockTemplate;
     static const char *EnumDefinitionTemplate;
     static const char *EnumFieldTemplate;
     static const char *ConstructorTemplate;

+ 79 - 21
src/lib/protobufobject.h

@@ -373,7 +373,8 @@ public:
 //####################################################
     void deserializeProperty(WireTypes wireType, const QMetaProperty &metaProperty, QByteArray::const_iterator &it)
     {
-        qProtoDebug() << __func__ << " wireType: " << wireType << " metaProperty: " << metaProperty.typeName() << "currentByte:" << QString::number((*it), 16);
+        QLatin1Literal typeName(metaProperty.typeName());
+        qProtoDebug() << __func__ << " wireType: " << wireType << " metaProperty: " << typeName << "currentByte:" << QString::number((*it), 16);
         QVariant newPropertyValue;
         int type = metaProperty.type();
         switch(type) {
@@ -381,14 +382,14 @@ public:
             if (wireType == Fixed32) {
                 newPropertyValue = deserializeFixed<fint32>(it);
             } else {
-                newPropertyValue = deserializeVarint<unsigned int>(it);
+                newPropertyValue = deserializeVarint<uint>(it);
             }
             break;
         case QMetaType::ULongLong:
             if (wireType == Fixed64) {
                 newPropertyValue = deserializeFixed<fint64>(it);
             } else {
-                //TODO: deserialize varint
+                newPropertyValue = deserializeVarint<uint64>(it);
             }
             break;
         case QMetaType::Float:
@@ -398,7 +399,20 @@ public:
             newPropertyValue = deserializeFixed<double>(it);
             break;
         case QMetaType::Int:
-            newPropertyValue = deserializeVarint<int>(it);
+            if (typeName == "sint32"
+                    || typeName == "qtprotobuf::sint32") {
+                newPropertyValue = deserializeVarintZigZag<sint32>(it);
+            } else {
+                newPropertyValue = deserializeVarint<int64>(it);
+            }
+            break;
+        case QMetaType::LongLong:
+            if (typeName == "sint64"
+                    || typeName == "qtprotobuf::sint64") {
+                newPropertyValue = deserializeVarintZigZag<sint64>(it);
+            } else {
+                newPropertyValue = deserializeVarint<int64>(it);
+            }
             break;
         case QMetaType::QString:
             newPropertyValue = QString::fromUtf8(deserializeLengthDelimited(it));
@@ -408,7 +422,7 @@ public:
             break;
         case QMetaType::User:
             newPropertyValue = metaProperty.read(this);
-            deserializeUserType(metaProperty.userType(), it, newPropertyValue);
+            deserializeUserType(metaProperty, it, newPropertyValue);
             break;
         case QMetaType::QByteArrayList: {
             QByteArrayList currentValue = metaProperty.read(this).value<QByteArrayList>();
@@ -448,11 +462,19 @@ public:
 
     template <typename V, typename UV = typename std::make_unsigned<V>::type,
               typename std::enable_if_t<std::is_signed<V>::value, int> = 0>
-    QVariant deserializeVarint(QByteArray::const_iterator &it) {
+    QVariant deserializeVarintZigZag(QByteArray::const_iterator &it) {
         qProtoDebug() << __func__ << "currentByte:" << QString::number((*it), 16);
         UV unsignedValue = deserializeVarintCommon<UV>(it);
         V value = (unsignedValue >> 1) ^ (-(unsignedValue & 1));
+        return QVariant::fromValue(value);
+    }
 
+    template <typename V, typename UV = typename std::make_unsigned<V>::type,
+              typename std::enable_if_t<std::is_signed<V>::value, int> = 0>
+    QVariant deserializeVarint(QByteArray::const_iterator &it) {
+        qProtoDebug() << __func__ << "currentByte:" << QString::number((*it), 16);
+        UV unsignedValue = deserializeVarintCommon<UV>(it);
+        V value = static_cast<V>(unsignedValue);
         return QVariant::fromValue(value);
     }
 
@@ -461,12 +483,15 @@ public:
         qProtoDebug() << __func__ << "currentByte:" << QString::number((*it), 16);
         V value = 0;
         int k = 0;
-        while((*it) & 0x80) {
-            value += ((*it) & 0x7f) << (7 * k);
-            ++k;
+        while(true) {
+            uint64_t byte = static_cast<uint64_t>(*it);
+            value += (byte & 0x7f) << k;
+            k += 7;
+            if(((*it) & 0x80) == 0) {
+                break;
+            }
             ++it;
         }
-        value += ((*it) & 0x7f) << (7 * k);
         ++it;
         return value;
     }
@@ -479,8 +504,10 @@ public:
         return result;
     }
 
-    void deserializeUserType(int userType, QByteArray::const_iterator& it, QVariant &newValue)
+    void 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);
 
         auto serializerIt = serializers.find(userType);
@@ -490,18 +517,40 @@ public:
         }
 
         if (userType == qMetaTypeId<int32List>()) {
-            newValue = deserializeVarintListType<int>(it);
+            if (typeName == "sint32List"
+                    || typeName == "qtprotobuf::sint32List") {
+                newValue = deserializeVarintListTypeZigZag<int32>(it);
+            } else {
+                newValue = deserializeVarintListType<int32>(it);
+            }
+        } else if (userType == qMetaTypeId<int64List>()) {
+            if (typeName == "sint64List"
+                    || typeName == "qtprotobuf::sint64List") {
+                newValue = deserializeVarintListTypeZigZag<int64>(it);
+            } else {
+                newValue = deserializeVarintListType<int64>(it);
+            }
+        } else if (userType == qMetaTypeId<uint32List>()) {
+            //TODO: Check if type is fixed
+            newValue = deserializeVarintListType<uint32>(it);
+        } else if (userType == qMetaTypeId<uint64List>()) {
+            //TODO: Check if type is fixed
+            newValue = deserializeVarintListType<uint64>(it);
         } else if(userType == qMetaTypeId<FloatList>()) {
             newValue = deserializeListType<float>(it);
         } else if(userType == qMetaTypeId<DoubleList>()) {
             newValue = deserializeListType<double>(it);
         } else {
-            auto value = reinterpret_cast<ProtobufObjectPrivate *>(QMetaType::create(userType));
-            value->deserializePrivate(deserializeLengthDelimited(it));
-            newValue = QVariant(userType, value);
+            newValue = deserializeProtobufObjectType(userType, it);
         }
     }
 
+    QVariant deserializeProtobufObjectType(int userType, QByteArray::const_iterator &it) {
+        auto value = reinterpret_cast<ProtobufObjectPrivate *>(QMetaType::create(userType));
+        value->deserializePrivate(deserializeLengthDelimited(it));
+        return QVariant(userType, value);
+    }
+
     template <typename V,
               typename std::enable_if_t<std::is_same<V, QString>::value
                                         || std::is_same<V, QByteArray>::value, int> = 0>
@@ -514,10 +563,7 @@ public:
               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;
+        return deserializeProtobufObjectType(qMetaTypeId<V>(), it);
     }
 
     template <typename V,
@@ -535,8 +581,7 @@ public:
         return QVariant::fromValue(out);
     }
 
-    template <typename V,
-              typename std::enable_if_t<std::is_same<V, int>::value, int> = 0>
+    template <typename V>
     QVariant deserializeVarintListType(QByteArray::const_iterator& it) {
         qProtoDebug() << __func__ << "currentByte:" << QString::number((*it), 16);
         QList<V> out;
@@ -548,6 +593,19 @@ public:
         }
         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);
+            out.append(variant.value<V>());
+        }
+        return QVariant::fromValue(out);
+    }
 };
 
 template <typename T>

File diff suppressed because it is too large
+ 23 - 23
tests/deserializationtest.cpp


Some files were not shown because too many files changed in this diff