• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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/flatbuffers.h"
20 #include "flatbuffers/idl.h"
21 #include "flatbuffers/util.h"
22 #include "flatbuffers/code_generators.h"
23 
24 #include "src/compiler/cpp_generator.h"
25 #include "src/compiler/go_generator.h"
26 
27 namespace flatbuffers {
28 
29 class FlatBufMethod : public grpc_generator::Method {
30  public:
31   enum Streaming { kNone, kClient, kServer, kBiDi };
32 
FlatBufMethod(const RPCCall * method)33   FlatBufMethod(const RPCCall *method)
34     : method_(method) {
35     streaming_ = kNone;
36     auto val = method_->attributes.Lookup("streaming");
37     if (val) {
38       if (val->constant == "client") streaming_ = kClient;
39       if (val->constant == "server") streaming_ = kServer;
40       if (val->constant == "bidi") streaming_ = kBiDi;
41     }
42   }
43 
name() const44   std::string name() const { return method_->name; }
45 
GRPCType(const StructDef & sd) const46   std::string GRPCType(const StructDef &sd) const {
47     return "flatbuffers::BufferRef<" + sd.name + ">";
48   }
49 
input_type_name() const50   std::string input_type_name() const {
51     return GRPCType(*method_->request);
52   }
output_type_name() const53   std::string output_type_name() const {
54     return GRPCType(*method_->response);
55   }
56 
input_name() const57   std::string input_name() const {
58     return (*method_->request).name;
59   }
60 
output_name() const61   std::string output_name() const {
62     return (*method_->response).name;
63   }
64 
NoStreaming() const65   bool NoStreaming() const { return streaming_ == kNone; }
ClientOnlyStreaming() const66   bool ClientOnlyStreaming() const { return streaming_ == kClient; }
ServerOnlyStreaming() const67   bool ServerOnlyStreaming() const { return streaming_ == kServer; }
BidiStreaming() const68   bool BidiStreaming() const { return streaming_ == kBiDi; }
69 
70  private:
71   const RPCCall *method_;
72   Streaming streaming_;
73 };
74 
75 class FlatBufService : public grpc_generator::Service {
76  public:
FlatBufService(const ServiceDef * service)77   FlatBufService(const ServiceDef *service) : service_(service) {}
78 
name() const79   std::string name() const { return service_->name; }
80 
method_count() const81   int method_count() const {
82     return static_cast<int>(service_->calls.vec.size());
83   };
84 
method(int i) const85   std::unique_ptr<const grpc_generator::Method> method(int i) const {
86     return std::unique_ptr<const grpc_generator::Method>(
87           new FlatBufMethod(service_->calls.vec[i]));
88   };
89 
90  private:
91   const ServiceDef *service_;
92 };
93 
94 class FlatBufPrinter : public grpc_generator::Printer {
95  public:
FlatBufPrinter(std::string * str)96   FlatBufPrinter(std::string *str)
97     : str_(str), escape_char_('$'), indent_(0) {}
98 
Print(const std::map<std::string,std::string> & vars,const char * string_template)99   void Print(const std::map<std::string, std::string> &vars,
100              const char *string_template) {
101     std::string s = string_template;
102     // Replace any occurrences of strings in "vars" that are surrounded
103     // by the escape character by what they're mapped to.
104     size_t pos;
105     while ((pos = s.find(escape_char_)) != std::string::npos) {
106       // Found an escape char, must also find the closing one.
107       size_t pos2 = s.find(escape_char_, pos + 1);
108       // If placeholder not closed, ignore.
109       if (pos2 == std::string::npos) break;
110       auto it = vars.find(s.substr(pos + 1, pos2 - pos - 1));
111       // If unknown placeholder, ignore.
112       if (it == vars.end()) break;
113       // Subtitute placeholder.
114       s.replace(pos, pos2 - pos + 1, it->second);
115     }
116     Print(s.c_str());
117   }
118 
Print(const char * s)119   void Print(const char *s) {
120     // Add this string, but for each part separated by \n, add indentation.
121     for (;;) {
122       // Current indentation.
123       str_->insert(str_->end(), indent_ * 2, ' ');
124       // See if this contains more than one line.
125       const char * lf = strchr(s, '\n');
126       if (lf) {
127         (*str_) += std::string(s, lf + 1);
128         s = lf + 1;
129         if (!*s) break;  // Only continue if there's more lines.
130       } else {
131         (*str_) += s;
132         break;
133       }
134     }
135   }
136 
Indent()137   void Indent() { indent_++; }
Outdent()138   void Outdent() { indent_--; assert(indent_ >= 0); }
139 
140  private:
141   std::string *str_;
142   char escape_char_;
143   int indent_;
144 };
145 
146 class FlatBufFile : public grpc_generator::File {
147  public:
FlatBufFile(const Parser & parser,const std::string & file_name)148   FlatBufFile(const Parser &parser, const std::string &file_name)
149     : parser_(parser), file_name_(file_name) {}
150   FlatBufFile &operator=(const FlatBufFile &);
151 
filename() const152   std::string filename() const { return file_name_; }
filename_without_ext() const153   std::string filename_without_ext() const {
154     return StripExtension(file_name_);
155   }
156 
message_header_ext() const157   std::string message_header_ext() const { return "_generated.h"; }
service_header_ext() const158   std::string service_header_ext() const { return ".grpc.fb.h"; }
159 
package() const160   std::string package() const {
161     return parser_.namespaces_.back()->GetFullyQualifiedName("");
162   }
163 
package_parts() const164   std::vector<std::string> package_parts() const {
165     return parser_.namespaces_.back()->components;
166   }
167 
additional_headers() const168   std::string additional_headers() const {
169     return "#include \"flatbuffers/grpc.h\"\n";
170   }
171 
additional_imports() const172   std::string additional_imports() const {
173     return "import \"github.com/google/flatbuffers/go\"";
174   }
175 
service_count() const176   int service_count() const {
177     return static_cast<int>(parser_.services_.vec.size());
178   };
179 
service(int i) const180   std::unique_ptr<const grpc_generator::Service> service(int i) const {
181     return std::unique_ptr<const grpc_generator::Service> (
182           new FlatBufService(parser_.services_.vec[i]));
183   }
184 
CreatePrinter(std::string * str) const185   std::unique_ptr<grpc_generator::Printer> CreatePrinter(std::string *str) const {
186     return std::unique_ptr<grpc_generator::Printer>(
187           new FlatBufPrinter(str));
188   }
189 
190  private:
191   const Parser &parser_;
192   const std::string &file_name_;
193 };
194 
195 class GoGRPCGenerator : public flatbuffers::BaseGenerator {
196  public:
GoGRPCGenerator(const Parser & parser,const std::string & path,const std::string & file_name)197   GoGRPCGenerator(const Parser &parser, const std::string &path,
198                   const std::string &file_name)
199     : BaseGenerator(parser, path, file_name, "", "" /*Unused*/),
200       parser_(parser), path_(path), file_name_(file_name) {}
201 
generate()202   bool generate() {
203     FlatBufFile file(parser_, file_name_);
204     grpc_go_generator::Parameters p;
205     p.custom_method_io_type = "flatbuffers.Builder";
206     for (int i = 0; i < file.service_count(); i++) {
207       auto service = file.service(i);
208       const Definition *def = parser_.services_.vec[i];
209       p.package_name = LastNamespacePart(*(def->defined_namespace));
210       std::string output = grpc_go_generator::GenerateServiceSource(&file, service.get(), &p);
211       std::string filename = NamespaceDir(*def->defined_namespace) + def->name + "_grpc.go";
212       if (!flatbuffers::SaveFile(filename.c_str(), output, false))
213         return false;
214     }
215     return true;
216   }
217 
218  protected:
219   const Parser &parser_;
220   const std::string &path_, &file_name_;
221 };
222 
GenerateGoGRPC(const Parser & parser,const std::string & path,const std::string & file_name)223 bool GenerateGoGRPC(const Parser &parser,
224                     const std::string &path,
225                     const std::string &file_name) {
226   int nservices = 0;
227   for (auto it = parser.services_.vec.begin();
228        it != parser.services_.vec.end(); ++it) {
229     if (!(*it)->generated) nservices++;
230   }
231   if (!nservices) return true;
232   return GoGRPCGenerator(parser, path, file_name).generate();
233 }
234 
GenerateCppGRPC(const Parser & parser,const std::string &,const std::string & file_name)235 bool GenerateCppGRPC(const Parser &parser,
236                   const std::string &/*path*/,
237                   const std::string &file_name) {
238 
239   int nservices = 0;
240   for (auto it = parser.services_.vec.begin();
241        it != parser.services_.vec.end(); ++it) {
242     if (!(*it)->generated) nservices++;
243   }
244   if (!nservices) return true;
245 
246   grpc_cpp_generator::Parameters generator_parameters;
247   // TODO(wvo): make the other parameters in this struct configurable.
248   generator_parameters.use_system_headers = true;
249 
250   FlatBufFile fbfile(parser, file_name);
251 
252   std::string header_code =
253       grpc_cpp_generator::GetHeaderPrologue(&fbfile, generator_parameters) +
254       grpc_cpp_generator::GetHeaderIncludes(&fbfile, generator_parameters) +
255       grpc_cpp_generator::GetHeaderServices(&fbfile, generator_parameters) +
256       grpc_cpp_generator::GetHeaderEpilogue(&fbfile, generator_parameters);
257 
258   std::string source_code =
259       grpc_cpp_generator::GetSourcePrologue(&fbfile, generator_parameters) +
260       grpc_cpp_generator::GetSourceIncludes(&fbfile, generator_parameters) +
261       grpc_cpp_generator::GetSourceServices(&fbfile, generator_parameters) +
262       grpc_cpp_generator::GetSourceEpilogue(&fbfile, generator_parameters);
263 
264   return flatbuffers::SaveFile((file_name + ".grpc.fb.h").c_str(),
265                                header_code, false) &&
266          flatbuffers::SaveFile((file_name + ".grpc.fb.cc").c_str(),
267                                source_code, false);
268 }
269 
270 }  // namespace flatbuffers
271 
272