Browse Source

Add service server generator

- Add basic server generator
- Add tolower function for std::string
- Few minor code fixes
Alexey Edelev 6 years ago
parent
commit
e582246f4a

+ 4 - 2
CMakeLists.txt

@@ -11,8 +11,10 @@ find_package(Protobuf)
 
 add_subdirectory("src/lib")
 
-add_executable(${PROJECT_NAME} "src/generator/main.cpp" "src/generator/generator.cpp"
-    "src/generator/classgeneratorbase.cpp")
+add_executable(${PROJECT_NAME} src/generator/main.cpp
+    src/generator/generator.cpp
+    src/generator/classgeneratorbase.cpp
+    src/generator/servergenerator.cpp)
 
 if (WIN32)
     #Needs to set path to protobuf libraries

+ 6 - 6
src/generator/classgeneratorbase.cpp

@@ -65,7 +65,7 @@ bool ClassGeneratorBase::producePropertyMap(const FieldDescriptor *field, Proper
     }
 
     std::string typeNameLower(typeName);
-    std::transform(std::begin(typeName), std::end(typeName), std::begin(typeNameLower), ::tolower);
+    utils::tolower(typeNameLower);
 
     std::string capProperty = field->camelcase_name();
     capProperty[0] = ::toupper(capProperty[0]);
@@ -87,13 +87,13 @@ void ClassGeneratorBase::printIncludes(const Descriptor *message, std::set<std::
     assert(message != nullptr);
     PropertyMap properties;
     std::set<std::string> existingIncludes;
-    std::string newinclude;
+    std::string newInclude;
     const char* includeTemplate;
     for (int i = 0; i < message->field_count(); i++) {
         const FieldDescriptor* field = message->field(i);
         if (producePropertyMap(field, properties)) {
             if (field->type() == FieldDescriptor::TYPE_MESSAGE) {
-                newinclude = properties["type_lower"];
+                newInclude = properties["type_lower"];
                 includeTemplate = InternalIncludeTemplate;
             } else if (field->type() == FieldDescriptor::TYPE_STRING) {
                 includeTemplate = ExternalIncludeTemplate;
@@ -102,9 +102,9 @@ void ClassGeneratorBase::printIncludes(const Descriptor *message, std::set<std::
             }
 
             if (!field->is_repeated()) {
-                if (existingIncludes.find(newinclude) == std::end(existingIncludes)) {
+                if (existingIncludes.find(newInclude) == std::end(existingIncludes)) {
                     mPrinter.Print(properties, includeTemplate);
-                    existingIncludes.insert(newinclude);
+                    existingIncludes.insert(newInclude);
                 }
             } else {
                 std::string stringInclude = properties["type"];
@@ -124,7 +124,7 @@ void ClassGeneratorBase::printIncludes(const Descriptor *message, std::set<std::
 
     for(auto modelTypeName : listModel) {
         std::string modelTypeNameLower(modelTypeName);
-        std::transform(std::begin(modelTypeNameLower), std::end(modelTypeNameLower), std::begin(modelTypeNameLower), ::tolower);
+        utils::tolower(modelTypeNameLower);
         mPrinter.Print({{"type_lower", modelTypeNameLower}}, InternalIncludeTemplate);
     }
 }

+ 1 - 0
src/generator/classgeneratorbase.h

@@ -26,6 +26,7 @@
 #pragma once
 
 #include <google/protobuf/io/printer.h>
+#include <memory>
 
 #include "templates.h"
 

+ 18 - 4
src/generator/generator.cpp

@@ -26,6 +26,8 @@
 #include "generator.h"
 #include "templates.h"
 #include "classgeneratorbase.h"
+#include "servergenerator.h"
+#include "utils.h"
 
 #include <google/protobuf/stubs/logging.h>
 #include <google/protobuf/stubs/common.h>
@@ -113,7 +115,7 @@ public:
 
     void printClassHeaderInclude() {
         std::string includeFileName = mClassName;
-        std::transform(std::begin(includeFileName), std::end(includeFileName), std::begin(includeFileName), ::tolower);
+        utils::tolower(includeFileName);
         mPrinter.Print({{"type_lower", includeFileName}}, InternalIncludeTemplate);
     }
 
@@ -180,7 +182,7 @@ bool QtGenerator::Generate(const FileDescriptor *file,
     for(int i = 0; i < file->message_type_count(); i++) {
         const Descriptor *message = file->message_type(i);
         std::string baseFilename(message->name());
-        std::transform(std::begin(baseFilename), std::end(baseFilename), std::begin(baseFilename), ::tolower);
+        utils::tolower(baseFilename);
 
         std::string filename = baseFilename + ".h";
         QtClassGenerator classGen(file->package(), message,
@@ -194,6 +196,18 @@ bool QtGenerator::Generate(const FileDescriptor *file,
         classSourceGen.run();
     }
 
+    for(int i = 0; i < file->service_count(); i++) {
+        const ServiceDescriptor* service = file->service(i);
+        std::string baseFilename(service->name());
+        utils::tolower(baseFilename);
+
+        std::string headeFilename = baseFilename + ".h";
+        ServerGenerator serverGen(file->package(), service,
+                                  std::move(std::unique_ptr<io::ZeroCopyOutputStream>(generatorContext->Open(headeFilename))));
+        serverGen.run();
+
+
+    }
     return true;
 }
 
@@ -201,14 +215,14 @@ bool QtGenerator::GenerateAll(const std::vector<const FileDescriptor *> &files,
 {
     std::string globalEnumsFilename = "globalenums.h";
     GlobalEnumsGenerator enumGen(std::move(std::unique_ptr<io::ZeroCopyOutputStream>(generatorContext->Open(globalEnumsFilename))));
-    std::unordered_map<std::string/*package*/, std::list<const FileDescriptor */*file*/>> packageList;
+    std::unordered_map<std::string/*package*/, std::list<const FileDescriptor *>> packageList;
     for (auto file : files) {
         packageList[file->package()].push_back(file);
     }
 
     for (auto package : packageList) {
         enumGen.startEnum(package.first);
-        for(auto file : package.second) {
+        for (auto file : package.second) {
             enumGen.run(file);
         }
         enumGen.encloseEnum();

+ 1 - 0
src/generator/generator.h

@@ -27,6 +27,7 @@
 
 #include <google/protobuf/compiler/code_generator.h>
 #include <string>
+#include <memory>
 
 namespace google { namespace protobuf {
 class FileDescriptor;

+ 71 - 0
src/generator/servergenerator.cpp

@@ -0,0 +1,71 @@
+/*
+ * MIT License
+ *
+ * Copyright (c) 2019 Alexey Edelev <semlanik@gmail.com>, Tatyana Borisova <tanusshhka@mail.ru>
+ *
+ * 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 "servergenerator.h"
+
+#include <google/protobuf/stubs/logging.h>
+#include <google/protobuf/stubs/common.h>
+#include <google/protobuf/io/printer.h>
+#include <google/protobuf/io/zero_copy_stream.h>
+#include <google/protobuf/descriptor.h>
+
+#include <unordered_set>
+
+#include "utils.h"
+#include "templates.h"
+
+using namespace ::google::protobuf;
+using namespace ::google::protobuf::compiler;
+
+using namespace qtprotobuf;
+
+//TODO: need to decompose common and non-common logic and fields of ClassGeneratorBase 
+ServerGenerator::ServerGenerator(const std::string &package, const ServiceDescriptor *service, std::unique_ptr<io::ZeroCopyOutputStream> out) :
+    ClassGeneratorBase(service->name(), std::move(out))
+  , mService(service)
+  , mPackage(package)
+{
+}
+
+void ServerGenerator::printIncludes(const ServiceDescriptor *service)
+{
+    std::unordered_set<std::string> includeSet;
+    for(int i = 0; i < service->method_count(); i++) {
+        const MethodDescriptor* method = service->method(i);
+        std::string inputTypeName = method->input_type()->name();
+        std::string outputTypeName = method->output_type()->name();
+        utils::tolower(inputTypeName);
+        utils::tolower(outputTypeName);
+        includeSet.insert(inputTypeName);
+        includeSet.insert(outputTypeName);
+    }
+
+    for(auto type : includeSet) {
+        mPrinter.Print({{"type_lower", type}}, InternalIncludeTemplate);
+    }
+}
+
+
+

+ 64 - 0
src/generator/servergenerator.h

@@ -0,0 +1,64 @@
+/*
+ * MIT License
+ *
+ * Copyright (c) 2019 Alexey Edelev <semlanik@gmail.com>, Tatyana Borisova <tanusshhka@mail.ru>
+ *
+ * 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 "classgeneratorbase.h"
+#include <string>
+#include <memory>
+#include <google/protobuf/io/printer.h>
+
+namespace google { namespace protobuf {
+class FieldDescriptor;
+class Descriptor;
+class ServiceDescriptor;
+class Message;
+namespace io {
+class ZeroCopyOutputStream;
+}}}
+
+namespace qtprotobuf {
+
+class ServerGenerator : public ClassGeneratorBase
+{
+    const google::protobuf::ServiceDescriptor *mService;
+    std::string mPackage;
+public:
+    ServerGenerator(const std::string &package, const google::protobuf::ServiceDescriptor *service, std::unique_ptr<google::protobuf::io::ZeroCopyOutputStream> out);
+
+    void run() {
+        printPreamble();
+        printIncludes(mService);
+        printNamespaces(mPackage);
+        mPrinter.Print({{"classname", mClassName}}, NonProtoClassDefinitionTemplate);
+        encloseClass();
+        enclose();
+    }
+
+protected:
+    void printIncludes(const google::protobuf::ServiceDescriptor *service);
+};
+
+}

+ 8 - 2
src/generator/utils.h

@@ -23,6 +23,8 @@
  * DEALINGS IN THE SOFTWARE.
  */
 
+#pragma once
+
 #include <string>
 #include <vector>
 #include <sstream>
@@ -30,7 +32,7 @@
 namespace qtprotobuf {
 namespace utils {
 
-void split(const std::string &str, std::vector<std::string> &container, char delim)
+static void split(const std::string &str, std::vector<std::string> &container, char delim)
 {
     std::stringstream stream(str);
     std::string token;
@@ -39,7 +41,7 @@ void split(const std::string &str, std::vector<std::string> &container, char del
     }
 }
 
-void replace(std::string & data, std::string from, std::string to) {
+static 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);
@@ -47,5 +49,9 @@ void replace(std::string & data, std::string from, std::string to) {
     }
 }
 
+static void tolower(std::string& str) {
+    std::transform(std::begin(str), std::end(str), std::begin(str), ::tolower);
+}
+
 }
 }

+ 9 - 0
tests/proto/testservice.proto

@@ -0,0 +1,9 @@
+syntax = "proto3";
+
+import "simpletest.proto";
+
+package qtprotobufnamespace.tests;
+
+service TestService {
+  rpc TestMethod (SimpleIntMessage) returns (SimpleIntMessage) {}
+} 

+ 1 - 1
tests/simpletest.cpp

@@ -125,7 +125,7 @@ TEST_F(SimpleTest, SimpleEnumsTest)
 {
     ASSERT_GT(GlobalEnums::staticMetaObject.enumeratorCount(), 0);
     QMetaEnum simpleEnum;
-    for(int i = 0; i < GlobalEnums::staticMetaObject.enumeratorCount(); i++) {
+    for (int i = 0; i < GlobalEnums::staticMetaObject.enumeratorCount(); i++) {
         QMetaEnum tmp = GlobalEnums::staticMetaObject.enumerator(i);
         if (QString(tmp.name()) == QString("TestEnum")) {
             simpleEnum = tmp;