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