2 * Copyright 2014 Google Inc. All rights reserved.
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
17 // independent from idl_parser, since this code is not needed for most clients
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 #include "src/compiler/python_generator.h"
27 #include "src/compiler/swift_generator.h"
28 #include "src/compiler/ts_generator.h"
31 # pragma warning(push)
32 # pragma warning(disable : 4512) // C4512: 'class' : assignment operator could
36 namespace flatbuffers {
38 class FlatBufMethod : public grpc_generator::Method {
40 enum Streaming { kNone, kClient, kServer, kBiDi };
42 FlatBufMethod(const RPCCall *method) : method_(method) {
44 auto val = method_->attributes.Lookup("streaming");
46 if (val->constant == "client") streaming_ = kClient;
47 if (val->constant == "server") streaming_ = kServer;
48 if (val->constant == "bidi") streaming_ = kBiDi;
52 grpc::string GetLeadingComments(const grpc::string) const { return ""; }
54 grpc::string GetTrailingComments(const grpc::string) const { return ""; }
56 std::vector<grpc::string> GetAllComments() const {
57 return method_->doc_comment;
60 std::string name() const { return method_->name; }
62 // TODO: This method need to incorporate namespace for C++ side. Other
63 // language bindings simply don't use this method.
64 std::string GRPCType(const StructDef &sd) const {
65 return "flatbuffers::grpc::Message<" + sd.name + ">";
68 std::vector<std::string> get_input_namespace_parts() const {
69 return (*method_->request).defined_namespace->components;
72 std::string get_input_type_name() const { return (*method_->request).name; }
74 std::vector<std::string> get_output_namespace_parts() const {
75 return (*method_->response).defined_namespace->components;
78 std::string get_output_type_name() const { return (*method_->response).name; }
80 bool get_module_and_message_path_input(grpc::string * /*str*/,
81 grpc::string /*generator_file_name*/,
82 bool /*generate_in_pb2_grpc*/,
83 grpc::string /*import_prefix*/) const {
87 bool get_module_and_message_path_output(
88 grpc::string * /*str*/, grpc::string /*generator_file_name*/,
89 bool /*generate_in_pb2_grpc*/, grpc::string /*import_prefix*/) const {
93 std::string get_fb_builder() const { return "builder"; }
95 std::string input_type_name() const { return GRPCType(*method_->request); }
97 std::string output_type_name() const { return GRPCType(*method_->response); }
99 bool NoStreaming() const { return streaming_ == kNone; }
101 bool ClientStreaming() const { return streaming_ == kClient; }
103 bool ServerStreaming() const { return streaming_ == kServer; }
105 bool BidiStreaming() const { return streaming_ == kBiDi; }
108 const RPCCall *method_;
109 Streaming streaming_;
112 class FlatBufService : public grpc_generator::Service {
114 FlatBufService(const ServiceDef *service) : service_(service) {}
116 grpc::string GetLeadingComments(const grpc::string) const { return ""; }
118 grpc::string GetTrailingComments(const grpc::string) const { return ""; }
120 std::vector<grpc::string> GetAllComments() const {
121 return service_->doc_comment;
124 std::vector<grpc::string> namespace_parts() const {
125 return service_->defined_namespace->components;
128 std::string name() const { return service_->name; }
129 bool is_internal() const {
130 return service_->Definition::attributes.Lookup("private") ? true : false;
133 int method_count() const {
134 return static_cast<int>(service_->calls.vec.size());
137 std::unique_ptr<const grpc_generator::Method> method(int i) const {
138 return std::unique_ptr<const grpc_generator::Method>(
139 new FlatBufMethod(service_->calls.vec[i]));
143 const ServiceDef *service_;
146 class FlatBufPrinter : public grpc_generator::Printer {
148 FlatBufPrinter(std::string *str, const char indentation_type)
152 indentation_size_(2),
153 indentation_type_(indentation_type) {}
155 void Print(const std::map<std::string, std::string> &vars,
156 const char *string_template) {
157 std::string s = string_template;
158 // Replace any occurrences of strings in "vars" that are surrounded
159 // by the escape character by what they're mapped to.
161 while ((pos = s.find(escape_char_)) != std::string::npos) {
162 // Found an escape char, must also find the closing one.
163 size_t pos2 = s.find(escape_char_, pos + 1);
164 // If placeholder not closed, ignore.
165 if (pos2 == std::string::npos) break;
166 auto it = vars.find(s.substr(pos + 1, pos2 - pos - 1));
167 // If unknown placeholder, ignore.
168 if (it == vars.end()) break;
169 // Subtitute placeholder.
170 s.replace(pos, pos2 - pos + 1, it->second);
175 void Print(const char *s) {
176 if (s == nullptr || *s == '\0') { return; }
177 // Add this string, but for each part separated by \n, add indentation.
179 // Current indentation.
180 str_->insert(str_->end(), indent_ * indentation_size_, indentation_type_);
181 // See if this contains more than one line.
182 const char *lf = strchr(s, '\n');
184 (*str_) += std::string(s, lf + 1);
186 if (!*s) break; // Only continue if there's more lines.
194 void SetIndentationSize(const int size) {
195 FLATBUFFERS_ASSERT(str_->empty());
196 indentation_size_ = size;
199 void Indent() { indent_++; }
203 FLATBUFFERS_ASSERT(indent_ >= 0);
210 int indentation_size_;
211 char indentation_type_;
214 class FlatBufFile : public grpc_generator::File {
225 FlatBufFile(const Parser &parser, const std::string &file_name,
227 : parser_(parser), file_name_(file_name), language_(language) {}
229 FlatBufFile &operator=(const FlatBufFile &);
231 grpc::string GetLeadingComments(const grpc::string) const { return ""; }
233 grpc::string GetTrailingComments(const grpc::string) const { return ""; }
235 std::vector<grpc::string> GetAllComments() const {
236 return std::vector<grpc::string>();
239 std::string filename() const { return file_name_; }
241 std::string filename_without_ext() const {
242 return StripExtension(file_name_);
245 std::string message_header_ext() const { return "_generated.h"; }
247 std::string service_header_ext() const { return ".grpc.fb.h"; }
249 std::string package() const {
250 return parser_.current_namespace_->GetFullyQualifiedName("");
253 std::vector<std::string> package_parts() const {
254 return parser_.current_namespace_->components;
257 std::string additional_headers() const {
260 return "#include \"flatbuffers/grpc.h\"\n";
263 return "import \"github.com/google/flatbuffers/go\"";
265 case kLanguageJava: {
266 return "import com.google.flatbuffers.grpc.FlatbuffersUtils;";
268 case kLanguagePython: {
271 case kLanguageSwift: {
281 int service_count() const {
282 return static_cast<int>(parser_.services_.vec.size());
285 std::unique_ptr<const grpc_generator::Service> service(int i) const {
286 return std::unique_ptr<const grpc_generator::Service>(
287 new FlatBufService(parser_.services_.vec[i]));
290 std::unique_ptr<grpc_generator::Printer> CreatePrinter(
291 std::string *str, const char indentation_type = ' ') const {
292 return std::unique_ptr<grpc_generator::Printer>(
293 new FlatBufPrinter(str, indentation_type));
297 const Parser &parser_;
298 const std::string &file_name_;
299 const Language language_;
302 class GoGRPCGenerator : public flatbuffers::BaseGenerator {
304 GoGRPCGenerator(const Parser &parser, const std::string &path,
305 const std::string &file_name)
306 : BaseGenerator(parser, path, file_name, "", "" /*Unused*/, "go"),
309 file_name_(file_name) {}
312 FlatBufFile file(parser_, file_name_, FlatBufFile::kLanguageGo);
313 grpc_go_generator::Parameters p;
314 p.custom_method_io_type = "flatbuffers.Builder";
315 for (int i = 0; i < file.service_count(); i++) {
316 auto service = file.service(i);
317 const Definition *def = parser_.services_.vec[i];
318 p.package_name = LastNamespacePart(*(def->defined_namespace));
320 def->defined_namespace->GetFullyQualifiedName(""); // file.package();
322 grpc_go_generator::GenerateServiceSource(&file, service.get(), &p);
323 std::string filename =
324 NamespaceDir(*def->defined_namespace) + def->name + "_grpc.go";
325 if (!flatbuffers::SaveFile(filename.c_str(), output, false)) return false;
331 const Parser &parser_;
332 const std::string &path_, &file_name_;
335 bool GenerateGoGRPC(const Parser &parser, const std::string &path,
336 const std::string &file_name) {
338 for (auto it = parser.services_.vec.begin(); it != parser.services_.vec.end();
340 if (!(*it)->generated) nservices++;
342 if (!nservices) return true;
343 return GoGRPCGenerator(parser, path, file_name).generate();
346 bool GenerateCppGRPC(const Parser &parser, const std::string &path,
347 const std::string &file_name) {
349 for (auto it = parser.services_.vec.begin(); it != parser.services_.vec.end();
351 if (!(*it)->generated) nservices++;
353 if (!nservices) return true;
355 grpc_cpp_generator::Parameters generator_parameters;
356 // TODO(wvo): make the other parameters in this struct configurable.
357 generator_parameters.use_system_headers = true;
359 FlatBufFile fbfile(parser, file_name, FlatBufFile::kLanguageCpp);
361 std::string header_code =
362 grpc_cpp_generator::GetHeaderPrologue(&fbfile, generator_parameters) +
363 grpc_cpp_generator::GetHeaderIncludes(&fbfile, generator_parameters) +
364 grpc_cpp_generator::GetHeaderServices(&fbfile, generator_parameters) +
365 grpc_cpp_generator::GetHeaderEpilogue(&fbfile, generator_parameters);
367 std::string source_code =
368 grpc_cpp_generator::GetSourcePrologue(&fbfile, generator_parameters) +
369 grpc_cpp_generator::GetSourceIncludes(&fbfile, generator_parameters) +
370 grpc_cpp_generator::GetSourceServices(&fbfile, generator_parameters) +
371 grpc_cpp_generator::GetSourceEpilogue(&fbfile, generator_parameters);
373 return flatbuffers::SaveFile((path + file_name + ".grpc.fb.h").c_str(),
374 header_code, false) &&
375 flatbuffers::SaveFile((path + file_name + ".grpc.fb.cc").c_str(),
379 class JavaGRPCGenerator : public flatbuffers::BaseGenerator {
381 JavaGRPCGenerator(const Parser &parser, const std::string &path,
382 const std::string &file_name)
383 : BaseGenerator(parser, path, file_name, "", "." /*separator*/, "java") {}
386 FlatBufFile file(parser_, file_name_, FlatBufFile::kLanguageJava);
387 grpc_java_generator::Parameters p;
388 for (int i = 0; i < file.service_count(); i++) {
389 auto service = file.service(i);
390 const Definition *def = parser_.services_.vec[i];
392 def->defined_namespace->GetFullyQualifiedName(""); // file.package();
394 grpc_java_generator::GenerateServiceSource(&file, service.get(), &p);
395 std::string filename =
396 NamespaceDir(*def->defined_namespace) + def->name + "Grpc.java";
397 if (!flatbuffers::SaveFile(filename.c_str(), output, false)) return false;
403 bool GenerateJavaGRPC(const Parser &parser, const std::string &path,
404 const std::string &file_name) {
406 for (auto it = parser.services_.vec.begin(); it != parser.services_.vec.end();
408 if (!(*it)->generated) nservices++;
410 if (!nservices) return true;
411 return JavaGRPCGenerator(parser, path, file_name).generate();
414 class PythonGRPCGenerator : public flatbuffers::BaseGenerator {
419 PythonGRPCGenerator(const Parser &parser, const std::string &filename)
420 : BaseGenerator(parser, "", filename, "", "" /*Unused*/, "swift") {}
425 "# Generated by the gRPC Python protocol compiler plugin. "
427 code_ += "import grpc\n";
429 FlatBufFile file(parser_, file_name_, FlatBufFile::kLanguagePython);
431 for (int i = 0; i < file.service_count(); i++) {
432 auto service = file.service(i);
433 code_ += grpc_python_generator::Generate(&file, service.get());
435 const auto final_code = code_.ToString();
436 const auto filename = GenerateFileName();
437 return SaveFile(filename.c_str(), final_code, false);
440 std::string GenerateFileName() {
441 std::string namespace_dir;
442 auto &namespaces = parser_.namespaces_.back()->components;
443 for (auto it = namespaces.begin(); it != namespaces.end(); ++it) {
444 if (it != namespaces.begin()) namespace_dir += kPathSeparator;
445 namespace_dir += *it;
447 std::string grpc_py_filename = namespace_dir;
448 if (!namespace_dir.empty()) grpc_py_filename += kPathSeparator;
449 return grpc_py_filename + file_name_ + "_grpc_fb.py";
453 bool GeneratePythonGRPC(const Parser &parser, const std::string & /*path*/,
454 const std::string &file_name) {
456 for (auto it = parser.services_.vec.begin(); it != parser.services_.vec.end();
458 if (!(*it)->generated) nservices++;
460 if (!nservices) return true;
462 return PythonGRPCGenerator(parser, file_name).generate();
465 class SwiftGRPCGenerator : public flatbuffers::BaseGenerator {
470 SwiftGRPCGenerator(const Parser &parser, const std::string &path,
471 const std::string &filename)
472 : BaseGenerator(parser, path, filename, "", "" /*Unused*/, "swift") {}
476 code_ += "// Generated GRPC code for FlatBuffers swift!";
477 code_ += grpc_swift_generator::GenerateHeader();
478 FlatBufFile file(parser_, file_name_, FlatBufFile::kLanguageSwift);
479 for (int i = 0; i < file.service_count(); i++) {
480 auto service = file.service(i);
481 code_ += grpc_swift_generator::Generate(&file, service.get());
483 const auto final_code = code_.ToString();
484 const auto filename = GeneratedFileName(path_, file_name_);
485 return SaveFile(filename.c_str(), final_code, false);
488 static std::string GeneratedFileName(const std::string &path,
489 const std::string &file_name) {
490 return path + file_name + ".grpc.swift";
494 bool GenerateSwiftGRPC(const Parser &parser, const std::string &path,
495 const std::string &file_name) {
497 for (auto it = parser.services_.vec.begin(); it != parser.services_.vec.end();
499 if (!(*it)->generated) nservices++;
501 if (!nservices) return true;
502 return SwiftGRPCGenerator(parser, path, file_name).generate();
505 class TSGRPCGenerator : public flatbuffers::BaseGenerator {
510 TSGRPCGenerator(const Parser &parser, const std::string &path,
511 const std::string &filename)
512 : BaseGenerator(parser, path, filename, "", "" /*Unused*/, "ts") {}
516 FlatBufFile file(parser_, file_name_, FlatBufFile::kLanguageTS);
518 for (int i = 0; i < file.service_count(); i++) {
519 auto service = file.service(i);
520 code_ += grpc_ts_generator::Generate(&file, service.get(), file_name_);
521 const auto ts_name = GeneratedFileName(path_, file_name_);
522 if (!SaveFile(ts_name.c_str(), code_.ToString(), false)) return false;
525 code_ += grpc_ts_generator::GenerateInterface(&file, service.get(),
527 const auto ts_interface_name = GeneratedFileName(path_, file_name_, true);
528 if (!SaveFile(ts_interface_name.c_str(), code_.ToString(), false))
534 static std::string GeneratedFileName(const std::string &path,
535 const std::string &file_name,
536 const bool is_interface = false) {
537 if (is_interface) return path + file_name + "_grpc.d.ts";
538 return path + file_name + "_grpc.js";
542 bool GenerateTSGRPC(const Parser &parser, const std::string &path,
543 const std::string &file_name) {
545 for (auto it = parser.services_.vec.begin(); it != parser.services_.vec.end();
547 if (!(*it)->generated) nservices++;
549 if (!nservices) return true;
550 return TSGRPCGenerator(parser, path, file_name).generate();
553 } // namespace flatbuffers
555 #if defined(_MSC_VER)
556 # pragma warning(pop)