Browse Source

Migrate to explicit lists

- Add explicit list types for int, float, double
- QByteArray, QString lists types used explicitly
- Add metatypes registrator
TODO: All repeated fields serialization is broken
Alexey Edelev 6 years ago
parent
commit
63cfcba764

+ 10 - 4
src/generator/classgeneratorbase.cpp

@@ -222,19 +222,25 @@ void ClassGeneratorBase::enclose()
 std::string ClassGeneratorBase::getTypeName(const FieldDescriptor *field)
 {
     assert(field != nullptr);
-    if (field->is_repeated()) {
-        return VariantList;
-    }
-
     std::string typeName;
     if (field->type() == FieldDescriptor::TYPE_MESSAGE) {
+        if (field->is_repeated()) {
+            return VariantList;
+        }
         typeName = field->message_type()->name();
     } else if (field->type() == FieldDescriptor::TYPE_ENUM) {
+        if (field->is_repeated()) {
+            return VariantList;
+        }
         typeName = field->enum_type()->name();
     } else {
         auto it = TypeReflection.find(field->type());
         if (it != std::end(TypeReflection)) {
             typeName = it->second;
+            if (field->is_repeated()) {
+                typeName[0] = ::toupper(typeName[0]);
+                typeName.append("List");
+            }
         }
     }
 

+ 2 - 2
src/lib/CMakeLists.txt

@@ -11,9 +11,9 @@ if (Qt5_POSITION_INDEPENDENT_CODE)
   set(CMAKE_POSITION_INDEPENDENT_CODE ON)
 endif()
 
-add_library(qtprotobufsupport "universallistmodelbase.cpp" "universallistmodel.cpp" "protobufobject.cpp")
+add_library(qtprotobufsupport universallistmodelbase.cpp universallistmodel.cpp protobufobject.cpp qtprotobuf.cpp)
 
-set_target_properties(qtprotobufsupport PROPERTIES PUBLIC_HEADER "universallistmodelbase.h;universallistmodel.h;protobufobject.h")
+set_target_properties(qtprotobufsupport PROPERTIES PUBLIC_HEADER "universallistmodelbase.h;universallistmodel.h;protobufobject.h;qtprotobuftypes.h;qtprotobuf.h")
 
 install(TARGETS qtprotobufsupport
     ARCHIVE DESTINATION lib

+ 16 - 6
src/lib/protobufobject.h

@@ -34,6 +34,7 @@
 #include <unordered_map>
 #include <memory>
 #include <type_traits>
+#include <qtprotobuftypes.h>
 
 #define ASSERT_FIELD_NUMBER(X) Q_ASSERT_X(X < 128 && X > 0 && X != NotUsedFieldIndex, T::staticMetaObject.className(), "fieldIndex is out of range")
 
@@ -115,12 +116,21 @@ protected:
 
     QByteArray serializeUserType(const QVariant& propertyValue) {
         int userType = propertyValue.userType();
-        Q_ASSERT_X(QMetaType::UnknownType == userType, staticMetaObject.className(), "Serialization of unknown user type");
-        const void *src = propertyValue.constData();
-        //TODO: each time huge objects will make own copies
-        //Probably generate fields reflection is better solution
-        auto value = std::unique_ptr<ProtobufObjectPrivate>(reinterpret_cast<ProtobufObjectPrivate *>(QMetaType::create(userType, src)));
-        return serializeLengthDelimited(value->serializePrivate());
+        if (userType == qMetaTypeId<IntList>()) {
+
+        } else if(userType == qMetaTypeId<FloatList>()) {
+
+        } else if(userType == qMetaTypeId<DoubleList>()) {
+
+        } else {
+            Q_ASSERT_X(QMetaType::UnknownType == userType, staticMetaObject.className(), "Serialization of unknown user type");
+            const void *src = propertyValue.constData();
+            //TODO: each time huge objects will make own copies
+            //Probably generate fields reflection is better solution
+            auto value = std::unique_ptr<ProtobufObjectPrivate>(reinterpret_cast<ProtobufObjectPrivate *>(QMetaType::create(userType, src)));
+            return serializeLengthDelimited(value->serializePrivate());
+        }
+        return QByteArray();
     }
 
     QByteArray serializeListType(const QVariantList& listValue, int &outFieldIndex)

+ 28 - 0
src/lib/qtprotobuf.cpp

@@ -0,0 +1,28 @@
+/*
+ * 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.
+ */
+
+#include <qtprotobuf.h>
+
+//bool qtprotobuf::QtProtobuf::registationDone = false;

+ 48 - 0
src/lib/qtprotobuf.h

@@ -0,0 +1,48 @@
+/*
+ * 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 <qtprotobuftypes.h>
+
+#include <QDebug>
+
+namespace qtprotobuf {
+
+class QtProtobuf {
+public:
+    static void init() {
+        static bool registationDone = false;
+        Q_ASSERT_X(!registationDone, "QtProtobuf", "Protobuf registation is already done");
+        if (!registationDone) {
+            qRegisterMetaType<IntList>("IntList");
+            qRegisterMetaType<FloatList>("FloatList");
+            qRegisterMetaType<DoubleList>("DoubleList");
+            registationDone = true;
+        }
+    }
+};
+
+}

+ 41 - 0
src/lib/qtprotobuftypes.h

@@ -0,0 +1,41 @@
+/*
+ * 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 <QList>
+#include <QMetaType>
+
+namespace qtprotobuf {
+
+using IntList = QList<int>;
+using FloatList = QList<float>;
+using DoubleList = QList<double>;
+
+}
+
+Q_DECLARE_METATYPE(qtprotobuf::IntList)
+Q_DECLARE_METATYPE(qtprotobuf::FloatList)
+Q_DECLARE_METATYPE(qtprotobuf::DoubleList)

+ 1 - 1
tests/CMakeLists.txt

@@ -48,6 +48,6 @@ add_executable(${testtarget} ${SOURCES} ${MOC_SOURCES} ${GENERATED_SOURCES} ${PR
 if (WIN32)
     target_link_libraries(${testtarget} "${GTEST_BOTH_LIBRARIES}/gmock_main.lib" "${GTEST_BOTH_LIBRARIES}/gmock.lib"  Qt5::Core)
 elseif (UNIX)
-    target_link_libraries(${testtarget} ${GTEST_BOTH_LIBRARIES} Qt5::Core)
+    target_link_libraries(${testtarget} ${GTEST_BOTH_LIBRARIES} qtprotobufsupport Qt5::Core)
 endif()
 add_dependencies(${testtarget} ${testgeneration})

+ 10 - 11
tests/serializationtest.cpp

@@ -36,11 +36,14 @@
 #include "repeatedbytesmessage.h"
 #include "repeatedfloatmessage.h"
 #include "repeatedcomplexmessage.h"
+#include "qtprotobuf.h"
 
 using namespace qtprotobuf::tests;
+using namespace qtprotobuf;
 
 SerializationTest::SerializationTest()
 {
+    qtprotobuf::QtProtobuf::init();
 }
 
 TEST_F(SerializationTest, IntMessageSerializeTest)
@@ -348,7 +351,7 @@ TEST_F(SerializationTest, RepeatedIntMessageTest)
 //    qDebug() << "result " << result.toHex();
     ASSERT_TRUE(result == QByteArray::fromHex("0a0702a00606080a0c"));
 
-    test.setTestRepeatedInt(QVariantList());
+    test.setTestRepeatedInt(IntList());
     result = test.serialize();
     ASSERT_TRUE(result.isEmpty());
 }
@@ -361,7 +364,7 @@ TEST_F(SerializationTest, RepeatedStringMessage)
 //    qDebug() << "result " << result.toHex();
     ASSERT_TRUE(result == QByteArray::fromHex("0a04616161610a0562626262620a036363630a066464646464640a056565656565"));
 
-    test.setTestRepeatedString(QVariantList());
+    test.setTestRepeatedString(QStringList());
     result = test.serialize();
     ASSERT_TRUE(result.isEmpty());
 }
@@ -369,14 +372,12 @@ TEST_F(SerializationTest, RepeatedStringMessage)
 TEST_F(SerializationTest, RepeatedDoubleMessageTest)
 {
     RepeatedDoubleMessage test;
-    test.setTestRepeatedDouble({QVariant::fromValue<double>(0.1), QVariant::fromValue<double>(0.2),
-                                QVariant::fromValue<double>(0.3), QVariant::fromValue<double>(0.4),
-                                QVariant::fromValue<double>(0.5)});
+    test.setTestRepeatedDouble({0.1, 0.2, 0.3, 0.4, 0.5});
     QByteArray result = test.serialize();
 //    qDebug() << "result " << result.toHex();
     ASSERT_TRUE(result == QByteArray::fromHex("0a289a9999999999b93f9a9999999999c93f333333333333d33f9a9999999999d93f000000000000e03f"));
 
-    test.setTestRepeatedDouble(QVariantList());
+    test.setTestRepeatedDouble(DoubleList());
     result = test.serialize();
     ASSERT_TRUE(result.isEmpty());
 }
@@ -391,7 +392,7 @@ TEST_F(SerializationTest, RepeatedBytesMessageTest)
     QByteArray result = test.serialize();
     ASSERT_TRUE(result == QByteArray::fromHex("0a060102030405060a04ffffffff0a05eaeaeaeaea0a06010203040506"));
 
-    test.setTestRepeatedBytes(QVariantList());
+    test.setTestRepeatedBytes(QByteArrayList());
     result = test.serialize();
     ASSERT_TRUE(result.isEmpty());
 
@@ -407,14 +408,12 @@ TEST_F(SerializationTest, RepeatedBytesMessageTest)
 TEST_F(SerializationTest, RepeatedFloatMessageTest)
 {
     RepeatedFloatMessage test;
-    test.setTestRepeatedFloat({QVariant::fromValue<float>(0.4f), QVariant::fromValue<float>(1.2f),
-                                QVariant::fromValue<float>(0.5f), QVariant::fromValue<float>(1.4f),
-                                QVariant::fromValue<float>(0.6f)});
+    test.setTestRepeatedFloat({0.4f, 1.2f, 0.5f, 1.4f, 0.6f});
     QByteArray result = test.serialize();
 //    qDebug() << "result " << result.toHex();
     ASSERT_TRUE(result == QByteArray::fromHex("0a14cdcccc3e9a99993f0000003f3333b33f9a99193f"));
 
-    test.setTestRepeatedFloat(QVariantList());
+    test.setTestRepeatedFloat(FloatList());
     result = test.serialize();
     ASSERT_TRUE(result.isEmpty());
 }

+ 7 - 4
tests/simpletest.cpp

@@ -33,14 +33,17 @@
 #include "repeatedintmessage.h"
 #include "simplebytesmessage.h"
 #include "globalenums.h"
+#include "qtprotobuf.h"
 #include <QVariantList>
 #include <QMetaProperty>
 
 using namespace qtprotobuf::tests;
 
+using namespace qtprotobuf;
 
 SimpleTest::SimpleTest()
 {
+    QtProtobuf::init();
 }
 
 TEST_F(SimpleTest, SimpleIntMessageTest)
@@ -130,9 +133,9 @@ TEST_F(SimpleTest, RepeatedIntMessageTest)
     const char* propertyName = "testRepeatedInt";
     RepeatedIntMessage test;
     int propertyNumber = RepeatedIntMessage::propertyOrdering.at(1); //See simpletest.proto
-    ASSERT_EQ(RepeatedIntMessage::staticMetaObject.property(propertyNumber).type(), QMetaType::QVariantList);
+    ASSERT_EQ(RepeatedIntMessage::staticMetaObject.property(propertyNumber).type(), qMetaTypeId<IntList>());
     ASSERT_STREQ(RepeatedIntMessage::staticMetaObject.property(propertyNumber).name(), propertyName);
-    ASSERT_TRUE(test.setProperty(propertyName, QVariant::fromValue<QVariantList>({1,2,3,4,5})));
-    ASSERT_TRUE(test.property(propertyName).toList() == QVariantList({1, 2, 3, 4, 5}));
-    ASSERT_TRUE(test.testRepeatedInt() == QVariantList({1, 2, 3, 4, 5}));
+    ASSERT_TRUE(test.setProperty(propertyName, QVariant::fromValue<IntList>({1,2,3,4,5})));
+    ASSERT_TRUE(test.property(propertyName).value<IntList>() == IntList({1, 2, 3, 4, 5}));
+    ASSERT_TRUE(test.testRepeatedInt() == IntList({1, 2, 3, 4, 5}));
 }