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"
28 # pragma warning(push)
29 # pragma warning(disable : 4512) // C4512: 'class' : assignment operator could
33 namespace flatbuffers {
35 class FlatBufMethod : public grpc_generator::Method {
37 enum Streaming { kNone, kClient, kServer, kBiDi };
39 FlatBufMethod(const RPCCall *method) : method_(method) {
41 auto val = method_->attributes.Lookup("streaming");
43 if (val->constant == "client") streaming_ = kClient;
44 if (val->constant == "server") streaming_ = kServer;
45 if (val->constant == "bidi") streaming_ = kBiDi;
49 grpc::string GetLeadingComments(const grpc::string) const { return ""; }
51 grpc::string GetTrailingComments(const grpc::string) const { return ""; }
53 std::vector<grpc::string> GetAllComments() const {
54 return method_->doc_comment;
57 std::string name() const { return method_->name; }
59 std::string GRPCType(const StructDef &sd) const {
60 return "flatbuffers::grpc::Message<" + sd.name + ">";
63 std::string get_input_type_name() const { return (*method_->request).name; }
65 std::string get_output_type_name() const { return (*method_->response).name; }
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 {
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 {
80 std::string input_type_name() const { return GRPCType(*method_->request); }
82 std::string output_type_name() const { return GRPCType(*method_->response); }
84 bool NoStreaming() const { return streaming_ == kNone; }
86 bool ClientStreaming() const { return streaming_ == kClient; }
88 bool ServerStreaming() const { return streaming_ == kServer; }
90 bool BidiStreaming() const { return streaming_ == kBiDi; }
93 const RPCCall *method_;
97 class FlatBufService : public grpc_generator::Service {
99 FlatBufService(const ServiceDef *service) : service_(service) {}
101 grpc::string GetLeadingComments(const grpc::string) const { return ""; }
103 grpc::string GetTrailingComments(const grpc::string) const { return ""; }
105 std::vector<grpc::string> GetAllComments() const {
106 return service_->doc_comment;
109 std::string name() const { return service_->name; }
111 int method_count() const {
112 return static_cast<int>(service_->calls.vec.size());
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]));
121 const ServiceDef *service_;
124 class FlatBufPrinter : public grpc_generator::Printer {
126 FlatBufPrinter(std::string *str) : str_(str), escape_char_('$'), indent_(0) {}
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.
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);
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.
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');
157 (*str_) += std::string(s, lf + 1);
159 if (!*s) break; // Only continue if there's more lines.
167 void Indent() { indent_++; }
171 FLATBUFFERS_ASSERT(indent_ >= 0);
180 class FlatBufFile : public grpc_generator::File {
182 enum Language { kLanguageGo, kLanguageCpp, kLanguageJava };
184 FlatBufFile(const Parser &parser, const std::string &file_name,
186 : parser_(parser), file_name_(file_name), language_(language) {}
188 FlatBufFile &operator=(const FlatBufFile &);
190 grpc::string GetLeadingComments(const grpc::string) const { return ""; }
192 grpc::string GetTrailingComments(const grpc::string) const { return ""; }
194 std::vector<grpc::string> GetAllComments() const {
195 return std::vector<grpc::string>();
198 std::string filename() const { return file_name_; }
200 std::string filename_without_ext() const {
201 return StripExtension(file_name_);
204 std::string message_header_ext() const { return "_generated.h"; }
206 std::string service_header_ext() const { return ".grpc.fb.h"; }
208 std::string package() const {
209 return parser_.current_namespace_->GetFullyQualifiedName("");
212 std::vector<std::string> package_parts() const {
213 return parser_.current_namespace_->components;
216 std::string additional_headers() const {
219 return "#include \"flatbuffers/grpc.h\"\n";
222 return "import \"github.com/google/flatbuffers/go\"";
224 case kLanguageJava: {
225 return "import com.google.flatbuffers.grpc.FlatbuffersUtils;";
231 int service_count() const {
232 return static_cast<int>(parser_.services_.vec.size());
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]));
240 std::unique_ptr<grpc_generator::Printer> CreatePrinter(
241 std::string *str) const {
242 return std::unique_ptr<grpc_generator::Printer>(new FlatBufPrinter(str));
246 const Parser &parser_;
247 const std::string &file_name_;
248 const Language language_;
251 class GoGRPCGenerator : public flatbuffers::BaseGenerator {
253 GoGRPCGenerator(const Parser &parser, const std::string &path,
254 const std::string &file_name)
255 : BaseGenerator(parser, path, file_name, "", "" /*Unused*/),
258 file_name_(file_name) {}
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));
269 def->defined_namespace->GetFullyQualifiedName(""); // file.package();
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;
280 const Parser &parser_;
281 const std::string &path_, &file_name_;
284 bool GenerateGoGRPC(const Parser &parser, const std::string &path,
285 const std::string &file_name) {
287 for (auto it = parser.services_.vec.begin(); it != parser.services_.vec.end();
289 if (!(*it)->generated) nservices++;
291 if (!nservices) return true;
292 return GoGRPCGenerator(parser, path, file_name).generate();
295 bool GenerateCppGRPC(const Parser &parser, const std::string &path,
296 const std::string &file_name) {
298 for (auto it = parser.services_.vec.begin(); it != parser.services_.vec.end();
300 if (!(*it)->generated) nservices++;
302 if (!nservices) return true;
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;
308 FlatBufFile fbfile(parser, file_name, FlatBufFile::kLanguageCpp);
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);
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);
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(),
328 class JavaGRPCGenerator : public flatbuffers::BaseGenerator {
330 JavaGRPCGenerator(const Parser &parser, const std::string &path,
331 const std::string &file_name)
332 : BaseGenerator(parser, path, file_name, "", "." /*separator*/) {}
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];
341 def->defined_namespace->GetFullyQualifiedName(""); // file.package();
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;
352 bool GenerateJavaGRPC(const Parser &parser, const std::string &path,
353 const std::string &file_name) {
355 for (auto it = parser.services_.vec.begin(); it != parser.services_.vec.end();
357 if (!(*it)->generated) nservices++;
359 if (!nservices) return true;
360 return JavaGRPCGenerator(parser, path, file_name).generate();
363 } // namespace flatbuffers
365 #if defined(_MSC_VER)
366 # pragma warning(pop)