Browse Source

Implement recursive serialization

Alexey Edelev 6 years ago
parent
commit
9625b26d7b

+ 12 - 1
src/generator/classgeneratorbase.cpp

@@ -149,7 +149,9 @@ void ClassGeneratorBase::printProperties(const Descriptor *message)
     for (int i = 0; i < message->field_count(); i++) {
         const FieldDescriptor* field = message->field(i);
         if (!isListType(field)) {
-            printField(field, PropertyTemplate);
+            const char* propertyTemplate = field->type() == FieldDescriptor::TYPE_MESSAGE ? MessagePropertyTemplate :
+                                                                                            PropertyTemplate;
+            printField(field, propertyTemplate);
         }
     }
     for (int i = 0; i < message->field_count(); i++) {
@@ -406,3 +408,12 @@ void ClassGeneratorBase::printComparisonOperators(const Descriptor *message)
 
     mPrinter.Print({{"type", mClassName}}, NotEqualOperatorTemplate);
 }
+
+void ClassGeneratorBase::printMetaTypeDeclaration(const std::string &package)
+{
+    std::string namespaces = package;
+    utils::replace(namespaces, std::string("."), std::string("::"));
+    mPrinter.Print({{"type", mClassName},
+                    {"namespaces", namespaces}}, DeclareMetaTypeTemplate);
+}
+

+ 2 - 0
src/generator/classgeneratorbase.h

@@ -58,6 +58,7 @@ protected:
     void printClass();
     void printField(const ::google::protobuf::FieldDescriptor *field, const char *fieldTemplate);
     void encloseClass();
+    void printMetaTypeDeclaration(const std::string &package);
     void enclose();
     std::string getTypeName(const ::google::protobuf::FieldDescriptor *field);
 
@@ -100,6 +101,7 @@ protected:
     void printProperties(const ::google::protobuf::Descriptor *message);
     void printConstructor();
     void printPublic();
+
     void Indent() {
         mPrinter.Indent();
         mPrinter.Indent();

+ 1 - 0
src/generator/generator.cpp

@@ -76,6 +76,7 @@ public:
         printFieldsOrderingDefinition();
         encloseClass();
         enclose();
+        printMetaTypeDeclaration(mPackage);
     }
 
     const std::set<std::string> &extractedModels() const {

+ 5 - 1
src/generator/templates.h

@@ -51,7 +51,7 @@ static const char *ClassDefinitionTemplate = "\nclass $classname$ : public Proto
                       "    Q_OBJECT\n";
 
 static const char *PropertyTemplate = "Q_PROPERTY($type$ $property_name$ READ $property_name$ WRITE set$property_name_cap$ NOTIFY $property_name$Changed)\n";
-static const char *MessagePropertyTemplate = "Q_PROPERTY($type$ * $property_name$ READ $property_name$ WRITE set$property_name_cap$ NOTIFY $property_name$Changed)\n";
+static const char *MessagePropertyTemplate = "Q_PROPERTY($type$ $property_name$ READ $property_name$ WRITE set$property_name_cap$ NOTIFY $property_name$Changed)\n";
 static const char *MemberTemplate = "$type$ m_$property_name$;\n";
 static const char *PublicBlockTemplate = "\npublic:\n";
 static const char *EnumDefinitionTemplate = "enum $enum$ {\n";
@@ -104,6 +104,10 @@ static const char *SimpleBlockEnclosureTemplate = "}\n\n";
 static const char *SemicolonBlockEnclosureTemplate = "};\n";
 static const char *EmptyBlockTemplate = "{}\n\n";
 
+static const char *DeclareMetaTypeTemplate = "#include <QMetaType>\n"
+                                             "Q_DECLARE_METATYPE($namespaces$::$type$)\n";
+
+
 static const std::unordered_map<::google::protobuf::FieldDescriptor::Type, std::string> TypeReflection = {
     {::google::protobuf::FieldDescriptor::TYPE_DOUBLE, "double"},
     {::google::protobuf::FieldDescriptor::TYPE_FLOAT, "float"},

+ 8 - 0
src/generator/utils.h

@@ -39,5 +39,13 @@ void split(const std::string &str, std::vector<std::string> &container, char del
     }
 }
 
+void replace(std::string & data, std::string from, std::string to) {
+    size_t pos = data.find(from);
+    while (pos != std::string::npos) {
+        data.replace(pos, from.size(), to);
+        pos = data.find(from, pos + to.size());
+    }
+}
+
 }
 }

+ 25 - 16
src/lib/protobufobject.h

@@ -48,50 +48,59 @@ enum WireTypes {
 class ProtobufObjectPrivate : public QObject {
 protected:
     explicit ProtobufObjectPrivate(QObject *parent = nullptr) : QObject(parent) {}
+
+public:
     virtual QByteArray serializePrivate() = 0;
 };
 
 template <typename T>
 class ProtobufObject : public ProtobufObjectPrivate
 {
-public:
-    explicit ProtobufObject(QObject *parent = nullptr) : ProtobufObjectPrivate(parent) {}
-
+protected:
     QByteArray serializePrivate() override {
-        serialize();
+        return serialize();
     }
 
+public:
+    explicit ProtobufObject(QObject *parent = nullptr) : ProtobufObjectPrivate(parent) {}
+
     QByteArray serialize() {
         QByteArray result;
         T* instance = dynamic_cast<T*>(this);
         for (auto field : T::propertyOrdering) {
             int propertyIndex = field.second;
             int fieldIndex = field.first;
-            const char* propertyName = T::staticMetaObject.property(propertyIndex).name();
-            switch (T::staticMetaObject.property(propertyIndex).type()) {
+            QMetaProperty metaProperty = T::staticMetaObject.property(propertyIndex);
+            const char* propertyName = metaProperty.name();
+            const QVariant& propertyValue = instance->property(propertyName);
+            switch (metaProperty.type()) {
             case QMetaType::Int:
-                result.append(serializeVarint(instance->property(propertyName).toInt(), fieldIndex));
+                result.append(serializeVarint(propertyValue.toInt(), fieldIndex));
                 break;
             case QMetaType::Float:
-                result.append(serializeFixed(instance->property(propertyName).toFloat(), fieldIndex));
+                result.append(serializeFixed(propertyValue.toFloat(), fieldIndex));
                 break;
             case QMetaType::Double:
-                result.append(serializeFixed(instance->property(propertyName).toDouble(), fieldIndex));
+                result.append(serializeFixed(propertyValue.toDouble(), fieldIndex));
                 break;
             case QMetaType::QString:
-                result.append(serializeLengthDelimited(instance->property(propertyName).toString().toUtf8(), fieldIndex));
+                result.append(serializeLengthDelimited(propertyValue.toString().toUtf8(), fieldIndex));
                 break;
             case QMetaType::QByteArray:
-                result.append(serializeLengthDelimited(instance->property(propertyName).toByteArray(), fieldIndex));
+                result.append(serializeLengthDelimited(propertyValue.toByteArray(), fieldIndex));
                 break;
             case QMetaType::User: {
-//TODO: Implement recurse serialization
-//                ProtobufObjectPrivate *value = instance->property(propertyName).value();
-//                result.append(serializeLengthDelimited(
-//                                  ->serializePrivate(),
-//                                  fieldIndex));
+                int userType = metaProperty.userType();
+                const void *src = propertyValue.constData();
+                //TODO: each time huge objects will make own copies
+                //Probably generate fields reflection is better solution
+                ProtobufObjectPrivate *value = reinterpret_cast<ProtobufObjectPrivate *>(QMetaType::create(userType, src));
+                result.append(serializeLengthDelimited(value->serializePrivate(),
+                                  fieldIndex));
             }
                 break;
+            default:
+                Q_ASSERT_X(false, T::staticMetaObject.className(), "Serialization of unknown type is impossible");
             }
         }
 

+ 5 - 0
tests/proto/simpletest.proto

@@ -18,6 +18,11 @@ message SimpleDoubleMessage {
     double testFieldDouble = 8;
 }
 
+message ComplexMessage {
+    int32 testFieldInt = 1;
+    SimpleStringMessage testComplexField = 2;
+}
+
 enum TestEnum {
     TEST_ENUM_VALUE0 = 0;
     TEST_ENUM_VALUE1 = 1;

File diff suppressed because it is too large
+ 2 - 1
tests/serializationtest.cpp


+ 6 - 0
tests/simpletest.cpp

@@ -29,6 +29,7 @@
 #include "simplestringmessage.h"
 #include "simplefloatmessage.h"
 #include "simpledoublemessage.h"
+#include "complexmessage.h"
 #include "globalenums.h"
 #include <QMetaProperty>
 
@@ -99,3 +100,8 @@ TEST_F(SimpleTest, SimpleEnumsTest)
     ASSERT_EQ(simpleEnum.value(3), 4);
     ASSERT_EQ(simpleEnum.value(4), 3);
 }
+
+TEST_F(SimpleTest, ComplexMessageTest)
+{
+    ComplexMessage msg;
+}

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