[C++] Refactor to conform to Google C++ style guide (#5608)
[platform/upstream/flatbuffers.git] / src / idl_gen_grpc.cpp
1 /*
2  * Copyright 2014 Google Inc. All rights reserved.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *     http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16
17 // independent from idl_parser, since this code is not needed for most clients
18
19 #include "flatbuffers/code_generators.h"
20 #include "flatbuffers/flatbuffers.h"
21 #include "flatbuffers/idl.h"
22 #include "flatbuffers/util.h"
23 #include "src/compiler/cpp_generator.h"
24 #include "src/compiler/go_generator.h"
25 #include "src/compiler/java_generator.h"
26
27 #if defined(_MSC_VER)
28 #  pragma warning(push)
29 #  pragma warning(disable : 4512)  // C4512: 'class' : assignment operator could
30 // not be generated
31 #endif
32
33 namespace flatbuffers {
34
35 class FlatBufMethod : public grpc_generator::Method {
36  public:
37   enum Streaming { kNone, kClient, kServer, kBiDi };
38
39   FlatBufMethod(const RPCCall *method) : method_(method) {
40     streaming_ = kNone;
41     auto val = method_->attributes.Lookup("streaming");
42     if (val) {
43       if (val->constant == "client") streaming_ = kClient;
44       if (val->constant == "server") streaming_ = kServer;
45       if (val->constant == "bidi") streaming_ = kBiDi;
46     }
47   }
48
49   grpc::string GetLeadingComments(const grpc::string) const { return ""; }
50
51   grpc::string GetTrailingComments(const grpc::string) const { return ""; }
52
53   std::vector<grpc::string> GetAllComments() const {
54     return method_->doc_comment;
55   }
56
57   std::string name() const { return method_->name; }
58
59   std::string GRPCType(const StructDef &sd) const {
60     return "flatbuffers::grpc::Message<" + sd.name + ">";
61   }
62
63   std::string get_input_type_name() const { return (*method_->request).name; }
64
65   std::string get_output_type_name() const { return (*method_->response).name; }
66
67   bool get_module_and_message_path_input(grpc::string * /*str*/,
68                                          grpc::string /*generator_file_name*/,
69                                          bool /*generate_in_pb2_grpc*/,
70                                          grpc::string /*import_prefix*/) const {
71     return true;
72   }
73
74   bool get_module_and_message_path_output(
75       grpc::string * /*str*/, grpc::string /*generator_file_name*/,
76       bool /*generate_in_pb2_grpc*/, grpc::string /*import_prefix*/) const {
77     return true;
78   }
79
80   std::string input_type_name() const { return GRPCType(*method_->request); }
81
82   std::string output_type_name() const { return GRPCType(*method_->response); }
83
84   bool NoStreaming() const { return streaming_ == kNone; }
85
86   bool ClientStreaming() const { return streaming_ == kClient; }
87
88   bool ServerStreaming() const { return streaming_ == kServer; }
89
90   bool BidiStreaming() const { return streaming_ == kBiDi; }
91
92  private:
93   const RPCCall *method_;
94   Streaming streaming_;
95 };
96
97 class FlatBufService : public grpc_generator::Service {
98  public:
99   FlatBufService(const ServiceDef *service) : service_(service) {}
100
101   grpc::string GetLeadingComments(const grpc::string) const { return ""; }
102
103   grpc::string GetTrailingComments(const grpc::string) const { return ""; }
104
105   std::vector<grpc::string> GetAllComments() const {
106     return service_->doc_comment;
107   }
108
109   std::string name() const { return service_->name; }
110
111   int method_count() const {
112     return static_cast<int>(service_->calls.vec.size());
113   }
114
115   std::unique_ptr<const grpc_generator::Method> method(int i) const {
116     return std::unique_ptr<const grpc_generator::Method>(
117         new FlatBufMethod(service_->calls.vec[i]));
118   }
119
120  private:
121   const ServiceDef *service_;
122 };
123
124 class FlatBufPrinter : public grpc_generator::Printer {
125  public:
126   FlatBufPrinter(std::string *str) : str_(str), escape_char_('$'), indent_(0) {}
127
128   void Print(const std::map<std::string, std::string> &vars,
129              const char *string_template) {
130     std::string s = string_template;
131     // Replace any occurrences of strings in "vars" that are surrounded
132     // by the escape character by what they're mapped to.
133     size_t pos;
134     while ((pos = s.find(escape_char_)) != std::string::npos) {
135       // Found an escape char, must also find the closing one.
136       size_t pos2 = s.find(escape_char_, pos + 1);
137       // If placeholder not closed, ignore.
138       if (pos2 == std::string::npos) break;
139       auto it = vars.find(s.substr(pos + 1, pos2 - pos - 1));
140       // If unknown placeholder, ignore.
141       if (it == vars.end()) break;
142       // Subtitute placeholder.
143       s.replace(pos, pos2 - pos + 1, it->second);
144     }
145     Print(s.c_str());
146   }
147
148   void Print(const char *s) {
149     if (s == nullptr || *s == '\0') { return; }
150     // Add this string, but for each part separated by \n, add indentation.
151     for (;;) {
152       // Current indentation.
153       str_->insert(str_->end(), indent_ * 2, ' ');
154       // See if this contains more than one line.
155       const char *lf = strchr(s, '\n');
156       if (lf) {
157         (*str_) += std::string(s, lf + 1);
158         s = lf + 1;
159         if (!*s) break;  // Only continue if there's more lines.
160       } else {
161         (*str_) += s;
162         break;
163       }
164     }
165   }
166
167   void Indent() { indent_++; }
168
169   void Outdent() {
170     indent_--;
171     FLATBUFFERS_ASSERT(indent_ >= 0);
172   }
173
174  private:
175   std::string *str_;
176   char escape_char_;
177   int indent_;
178 };
179
180 class FlatBufFile : public grpc_generator::File {
181  public:
182   enum Language { kLanguageGo, kLanguageCpp, kLanguageJava };
183
184   FlatBufFile(const Parser &parser, const std::string &file_name,
185               Language language)
186       : parser_(parser), file_name_(file_name), language_(language) {}
187
188   FlatBufFile &operator=(const FlatBufFile &);
189
190   grpc::string GetLeadingComments(const grpc::string) const { return ""; }
191
192   grpc::string GetTrailingComments(const grpc::string) const { return ""; }
193
194   std::vector<grpc::string> GetAllComments() const {
195     return std::vector<grpc::string>();
196   }
197
198   std::string filename() const { return file_name_; }
199
200   std::string filename_without_ext() const {
201     return StripExtension(file_name_);
202   }
203
204   std::string message_header_ext() const { return "_generated.h"; }
205
206   std::string service_header_ext() const { return ".grpc.fb.h"; }
207
208   std::string package() const {
209     return parser_.current_namespace_->GetFullyQualifiedName("");
210   }
211
212   std::vector<std::string> package_parts() const {
213     return parser_.current_namespace_->components;
214   }
215
216   std::string additional_headers() const {
217     switch (language_) {
218       case kLanguageCpp: {
219         return "#include \"flatbuffers/grpc.h\"\n";
220       }
221       case kLanguageGo: {
222         return "import \"github.com/google/flatbuffers/go\"";
223       }
224       case kLanguageJava: {
225         return "import com.google.flatbuffers.grpc.FlatbuffersUtils;";
226       }
227     }
228     return "";
229   }
230
231   int service_count() const {
232     return static_cast<int>(parser_.services_.vec.size());
233   }
234
235   std::unique_ptr<const grpc_generator::Service> service(int i) const {
236     return std::unique_ptr<const grpc_generator::Service>(
237         new FlatBufService(parser_.services_.vec[i]));
238   }
239
240   std::unique_ptr<grpc_generator::Printer> CreatePrinter(
241       std::string *str) const {
242     return std::unique_ptr<grpc_generator::Printer>(new FlatBufPrinter(str));
243   }
244
245  private:
246   const Parser &parser_;
247   const std::string &file_name_;
248   const Language language_;
249 };
250
251 class GoGRPCGenerator : public flatbuffers::BaseGenerator {
252  public:
253   GoGRPCGenerator(const Parser &parser, const std::string &path,
254                   const std::string &file_name)
255       : BaseGenerator(parser, path, file_name, "", "" /*Unused*/),
256         parser_(parser),
257         path_(path),
258         file_name_(file_name) {}
259
260   bool generate() {
261     FlatBufFile file(parser_, file_name_, FlatBufFile::kLanguageGo);
262     grpc_go_generator::Parameters p;
263     p.custom_method_io_type = "flatbuffers.Builder";
264     for (int i = 0; i < file.service_count(); i++) {
265       auto service = file.service(i);
266       const Definition *def = parser_.services_.vec[i];
267       p.package_name = LastNamespacePart(*(def->defined_namespace));
268       p.service_prefix =
269           def->defined_namespace->GetFullyQualifiedName("");  // file.package();
270       std::string output =
271           grpc_go_generator::GenerateServiceSource(&file, service.get(), &p);
272       std::string filename =
273           NamespaceDir(*def->defined_namespace) + def->name + "_grpc.go";
274       if (!flatbuffers::SaveFile(filename.c_str(), output, false)) return false;
275     }
276     return true;
277   }
278
279  protected:
280   const Parser &parser_;
281   const std::string &path_, &file_name_;
282 };
283
284 bool GenerateGoGRPC(const Parser &parser, const std::string &path,
285                     const std::string &file_name) {
286   int nservices = 0;
287   for (auto it = parser.services_.vec.begin(); it != parser.services_.vec.end();
288        ++it) {
289     if (!(*it)->generated) nservices++;
290   }
291   if (!nservices) return true;
292   return GoGRPCGenerator(parser, path, file_name).generate();
293 }
294
295 bool GenerateCppGRPC(const Parser &parser, const std::string &path,
296                      const std::string &file_name) {
297   int nservices = 0;
298   for (auto it = parser.services_.vec.begin(); it != parser.services_.vec.end();
299        ++it) {
300     if (!(*it)->generated) nservices++;
301   }
302   if (!nservices) return true;
303
304   grpc_cpp_generator::Parameters generator_parameters;
305   // TODO(wvo): make the other parameters in this struct configurable.
306   generator_parameters.use_system_headers = true;
307
308   FlatBufFile fbfile(parser, file_name, FlatBufFile::kLanguageCpp);
309
310   std::string header_code =
311       grpc_cpp_generator::GetHeaderPrologue(&fbfile, generator_parameters) +
312       grpc_cpp_generator::GetHeaderIncludes(&fbfile, generator_parameters) +
313       grpc_cpp_generator::GetHeaderServices(&fbfile, generator_parameters) +
314       grpc_cpp_generator::GetHeaderEpilogue(&fbfile, generator_parameters);
315
316   std::string source_code =
317       grpc_cpp_generator::GetSourcePrologue(&fbfile, generator_parameters) +
318       grpc_cpp_generator::GetSourceIncludes(&fbfile, generator_parameters) +
319       grpc_cpp_generator::GetSourceServices(&fbfile, generator_parameters) +
320       grpc_cpp_generator::GetSourceEpilogue(&fbfile, generator_parameters);
321
322   return flatbuffers::SaveFile((path + file_name + ".grpc.fb.h").c_str(),
323                                header_code, false) &&
324          flatbuffers::SaveFile((path + file_name + ".grpc.fb.cc").c_str(),
325                                source_code, false);
326 }
327
328 class JavaGRPCGenerator : public flatbuffers::BaseGenerator {
329  public:
330   JavaGRPCGenerator(const Parser &parser, const std::string &path,
331                     const std::string &file_name)
332       : BaseGenerator(parser, path, file_name, "", "." /*separator*/) {}
333
334   bool generate() {
335     FlatBufFile file(parser_, file_name_, FlatBufFile::kLanguageJava);
336     grpc_java_generator::Parameters p;
337     for (int i = 0; i < file.service_count(); i++) {
338       auto service = file.service(i);
339       const Definition *def = parser_.services_.vec[i];
340       p.package_name =
341           def->defined_namespace->GetFullyQualifiedName("");  // file.package();
342       std::string output =
343           grpc_java_generator::GenerateServiceSource(&file, service.get(), &p);
344       std::string filename =
345           NamespaceDir(*def->defined_namespace) + def->name + "Grpc.java";
346       if (!flatbuffers::SaveFile(filename.c_str(), output, false)) return false;
347     }
348     return true;
349   }
350 };
351
352 bool GenerateJavaGRPC(const Parser &parser, const std::string &path,
353                       const std::string &file_name) {
354   int nservices = 0;
355   for (auto it = parser.services_.vec.begin(); it != parser.services_.vec.end();
356        ++it) {
357     if (!(*it)->generated) nservices++;
358   }
359   if (!nservices) return true;
360   return JavaGRPCGenerator(parser, path, file_name).generate();
361 }
362
363 }  // namespace flatbuffers
364
365 #if defined(_MSC_VER)
366 #  pragma warning(pop)
367 #endif