xref: /aosp_15_r20/external/flatbuffers/src/idl_gen_grpc.cpp (revision 890232f25432b36107d06881e0a25aaa6b473652)
1*890232f2SAndroid Build Coastguard Worker /*
2*890232f2SAndroid Build Coastguard Worker  * Copyright 2014 Google Inc. All rights reserved.
3*890232f2SAndroid Build Coastguard Worker  *
4*890232f2SAndroid Build Coastguard Worker  * Licensed under the Apache License, Version 2.0 (the "License");
5*890232f2SAndroid Build Coastguard Worker  * you may not use this file except in compliance with the License.
6*890232f2SAndroid Build Coastguard Worker  * You may obtain a copy of the License at
7*890232f2SAndroid Build Coastguard Worker  *
8*890232f2SAndroid Build Coastguard Worker  *     http://www.apache.org/licenses/LICENSE-2.0
9*890232f2SAndroid Build Coastguard Worker  *
10*890232f2SAndroid Build Coastguard Worker  * Unless required by applicable law or agreed to in writing, software
11*890232f2SAndroid Build Coastguard Worker  * distributed under the License is distributed on an "AS IS" BASIS,
12*890232f2SAndroid Build Coastguard Worker  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*890232f2SAndroid Build Coastguard Worker  * See the License for the specific language governing permissions and
14*890232f2SAndroid Build Coastguard Worker  * limitations under the License.
15*890232f2SAndroid Build Coastguard Worker  */
16*890232f2SAndroid Build Coastguard Worker 
17*890232f2SAndroid Build Coastguard Worker // independent from idl_parser, since this code is not needed for most clients
18*890232f2SAndroid Build Coastguard Worker 
19*890232f2SAndroid Build Coastguard Worker #include "flatbuffers/code_generators.h"
20*890232f2SAndroid Build Coastguard Worker #include "flatbuffers/flatbuffers.h"
21*890232f2SAndroid Build Coastguard Worker #include "flatbuffers/idl.h"
22*890232f2SAndroid Build Coastguard Worker #include "flatbuffers/util.h"
23*890232f2SAndroid Build Coastguard Worker #include "src/compiler/cpp_generator.h"
24*890232f2SAndroid Build Coastguard Worker #include "src/compiler/go_generator.h"
25*890232f2SAndroid Build Coastguard Worker #include "src/compiler/java_generator.h"
26*890232f2SAndroid Build Coastguard Worker #include "src/compiler/python_generator.h"
27*890232f2SAndroid Build Coastguard Worker #include "src/compiler/swift_generator.h"
28*890232f2SAndroid Build Coastguard Worker #include "src/compiler/ts_generator.h"
29*890232f2SAndroid Build Coastguard Worker 
30*890232f2SAndroid Build Coastguard Worker #if defined(_MSC_VER)
31*890232f2SAndroid Build Coastguard Worker #  pragma warning(push)
32*890232f2SAndroid Build Coastguard Worker #  pragma warning(disable : 4512)  // C4512: 'class' : assignment operator could
33*890232f2SAndroid Build Coastguard Worker // not be generated
34*890232f2SAndroid Build Coastguard Worker #endif
35*890232f2SAndroid Build Coastguard Worker 
36*890232f2SAndroid Build Coastguard Worker namespace flatbuffers {
37*890232f2SAndroid Build Coastguard Worker 
38*890232f2SAndroid Build Coastguard Worker class FlatBufMethod : public grpc_generator::Method {
39*890232f2SAndroid Build Coastguard Worker  public:
40*890232f2SAndroid Build Coastguard Worker   enum Streaming { kNone, kClient, kServer, kBiDi };
41*890232f2SAndroid Build Coastguard Worker 
FlatBufMethod(const RPCCall * method)42*890232f2SAndroid Build Coastguard Worker   FlatBufMethod(const RPCCall *method) : method_(method) {
43*890232f2SAndroid Build Coastguard Worker     streaming_ = kNone;
44*890232f2SAndroid Build Coastguard Worker     auto val = method_->attributes.Lookup("streaming");
45*890232f2SAndroid Build Coastguard Worker     if (val) {
46*890232f2SAndroid Build Coastguard Worker       if (val->constant == "client") streaming_ = kClient;
47*890232f2SAndroid Build Coastguard Worker       if (val->constant == "server") streaming_ = kServer;
48*890232f2SAndroid Build Coastguard Worker       if (val->constant == "bidi") streaming_ = kBiDi;
49*890232f2SAndroid Build Coastguard Worker     }
50*890232f2SAndroid Build Coastguard Worker   }
51*890232f2SAndroid Build Coastguard Worker 
GetLeadingComments(const grpc::string) const52*890232f2SAndroid Build Coastguard Worker   grpc::string GetLeadingComments(const grpc::string) const { return ""; }
53*890232f2SAndroid Build Coastguard Worker 
GetTrailingComments(const grpc::string) const54*890232f2SAndroid Build Coastguard Worker   grpc::string GetTrailingComments(const grpc::string) const { return ""; }
55*890232f2SAndroid Build Coastguard Worker 
GetAllComments() const56*890232f2SAndroid Build Coastguard Worker   std::vector<grpc::string> GetAllComments() const {
57*890232f2SAndroid Build Coastguard Worker     return method_->doc_comment;
58*890232f2SAndroid Build Coastguard Worker   }
59*890232f2SAndroid Build Coastguard Worker 
name() const60*890232f2SAndroid Build Coastguard Worker   std::string name() const { return method_->name; }
61*890232f2SAndroid Build Coastguard Worker 
62*890232f2SAndroid Build Coastguard Worker   // TODO: This method need to incorporate namespace for C++ side. Other
63*890232f2SAndroid Build Coastguard Worker   // language bindings simply don't use this method.
GRPCType(const StructDef & sd) const64*890232f2SAndroid Build Coastguard Worker   std::string GRPCType(const StructDef &sd) const {
65*890232f2SAndroid Build Coastguard Worker     return "flatbuffers::grpc::Message<" + sd.name + ">";
66*890232f2SAndroid Build Coastguard Worker   }
67*890232f2SAndroid Build Coastguard Worker 
get_input_namespace_parts() const68*890232f2SAndroid Build Coastguard Worker   std::vector<std::string> get_input_namespace_parts() const {
69*890232f2SAndroid Build Coastguard Worker     return (*method_->request).defined_namespace->components;
70*890232f2SAndroid Build Coastguard Worker   }
71*890232f2SAndroid Build Coastguard Worker 
get_input_type_name() const72*890232f2SAndroid Build Coastguard Worker   std::string get_input_type_name() const { return (*method_->request).name; }
73*890232f2SAndroid Build Coastguard Worker 
get_output_namespace_parts() const74*890232f2SAndroid Build Coastguard Worker   std::vector<std::string> get_output_namespace_parts() const {
75*890232f2SAndroid Build Coastguard Worker     return (*method_->response).defined_namespace->components;
76*890232f2SAndroid Build Coastguard Worker   }
77*890232f2SAndroid Build Coastguard Worker 
get_output_type_name() const78*890232f2SAndroid Build Coastguard Worker   std::string get_output_type_name() const { return (*method_->response).name; }
79*890232f2SAndroid Build Coastguard Worker 
get_module_and_message_path_input(grpc::string *,grpc::string,bool,grpc::string) const80*890232f2SAndroid Build Coastguard Worker   bool get_module_and_message_path_input(grpc::string * /*str*/,
81*890232f2SAndroid Build Coastguard Worker                                          grpc::string /*generator_file_name*/,
82*890232f2SAndroid Build Coastguard Worker                                          bool /*generate_in_pb2_grpc*/,
83*890232f2SAndroid Build Coastguard Worker                                          grpc::string /*import_prefix*/) const {
84*890232f2SAndroid Build Coastguard Worker     return true;
85*890232f2SAndroid Build Coastguard Worker   }
86*890232f2SAndroid Build Coastguard Worker 
get_module_and_message_path_output(grpc::string *,grpc::string,bool,grpc::string) const87*890232f2SAndroid Build Coastguard Worker   bool get_module_and_message_path_output(
88*890232f2SAndroid Build Coastguard Worker       grpc::string * /*str*/, grpc::string /*generator_file_name*/,
89*890232f2SAndroid Build Coastguard Worker       bool /*generate_in_pb2_grpc*/, grpc::string /*import_prefix*/) const {
90*890232f2SAndroid Build Coastguard Worker     return true;
91*890232f2SAndroid Build Coastguard Worker   }
92*890232f2SAndroid Build Coastguard Worker 
get_fb_builder() const93*890232f2SAndroid Build Coastguard Worker   std::string get_fb_builder() const { return "builder"; }
94*890232f2SAndroid Build Coastguard Worker 
input_type_name() const95*890232f2SAndroid Build Coastguard Worker   std::string input_type_name() const { return GRPCType(*method_->request); }
96*890232f2SAndroid Build Coastguard Worker 
output_type_name() const97*890232f2SAndroid Build Coastguard Worker   std::string output_type_name() const { return GRPCType(*method_->response); }
98*890232f2SAndroid Build Coastguard Worker 
NoStreaming() const99*890232f2SAndroid Build Coastguard Worker   bool NoStreaming() const { return streaming_ == kNone; }
100*890232f2SAndroid Build Coastguard Worker 
ClientStreaming() const101*890232f2SAndroid Build Coastguard Worker   bool ClientStreaming() const { return streaming_ == kClient; }
102*890232f2SAndroid Build Coastguard Worker 
ServerStreaming() const103*890232f2SAndroid Build Coastguard Worker   bool ServerStreaming() const { return streaming_ == kServer; }
104*890232f2SAndroid Build Coastguard Worker 
BidiStreaming() const105*890232f2SAndroid Build Coastguard Worker   bool BidiStreaming() const { return streaming_ == kBiDi; }
106*890232f2SAndroid Build Coastguard Worker 
107*890232f2SAndroid Build Coastguard Worker  private:
108*890232f2SAndroid Build Coastguard Worker   const RPCCall *method_;
109*890232f2SAndroid Build Coastguard Worker   Streaming streaming_;
110*890232f2SAndroid Build Coastguard Worker };
111*890232f2SAndroid Build Coastguard Worker 
112*890232f2SAndroid Build Coastguard Worker class FlatBufService : public grpc_generator::Service {
113*890232f2SAndroid Build Coastguard Worker  public:
FlatBufService(const ServiceDef * service)114*890232f2SAndroid Build Coastguard Worker   FlatBufService(const ServiceDef *service) : service_(service) {}
115*890232f2SAndroid Build Coastguard Worker 
GetLeadingComments(const grpc::string) const116*890232f2SAndroid Build Coastguard Worker   grpc::string GetLeadingComments(const grpc::string) const { return ""; }
117*890232f2SAndroid Build Coastguard Worker 
GetTrailingComments(const grpc::string) const118*890232f2SAndroid Build Coastguard Worker   grpc::string GetTrailingComments(const grpc::string) const { return ""; }
119*890232f2SAndroid Build Coastguard Worker 
GetAllComments() const120*890232f2SAndroid Build Coastguard Worker   std::vector<grpc::string> GetAllComments() const {
121*890232f2SAndroid Build Coastguard Worker     return service_->doc_comment;
122*890232f2SAndroid Build Coastguard Worker   }
123*890232f2SAndroid Build Coastguard Worker 
namespace_parts() const124*890232f2SAndroid Build Coastguard Worker   std::vector<grpc::string> namespace_parts() const {
125*890232f2SAndroid Build Coastguard Worker     return service_->defined_namespace->components;
126*890232f2SAndroid Build Coastguard Worker   }
127*890232f2SAndroid Build Coastguard Worker 
name() const128*890232f2SAndroid Build Coastguard Worker   std::string name() const { return service_->name; }
is_internal() const129*890232f2SAndroid Build Coastguard Worker   bool is_internal() const {
130*890232f2SAndroid Build Coastguard Worker     return service_->Definition::attributes.Lookup("private") ? true : false;
131*890232f2SAndroid Build Coastguard Worker   }
132*890232f2SAndroid Build Coastguard Worker 
method_count() const133*890232f2SAndroid Build Coastguard Worker   int method_count() const {
134*890232f2SAndroid Build Coastguard Worker     return static_cast<int>(service_->calls.vec.size());
135*890232f2SAndroid Build Coastguard Worker   }
136*890232f2SAndroid Build Coastguard Worker 
method(int i) const137*890232f2SAndroid Build Coastguard Worker   std::unique_ptr<const grpc_generator::Method> method(int i) const {
138*890232f2SAndroid Build Coastguard Worker     return std::unique_ptr<const grpc_generator::Method>(
139*890232f2SAndroid Build Coastguard Worker         new FlatBufMethod(service_->calls.vec[i]));
140*890232f2SAndroid Build Coastguard Worker   }
141*890232f2SAndroid Build Coastguard Worker 
142*890232f2SAndroid Build Coastguard Worker  private:
143*890232f2SAndroid Build Coastguard Worker   const ServiceDef *service_;
144*890232f2SAndroid Build Coastguard Worker };
145*890232f2SAndroid Build Coastguard Worker 
146*890232f2SAndroid Build Coastguard Worker class FlatBufPrinter : public grpc_generator::Printer {
147*890232f2SAndroid Build Coastguard Worker  public:
FlatBufPrinter(std::string * str,const char indentation_type)148*890232f2SAndroid Build Coastguard Worker   FlatBufPrinter(std::string *str, const char indentation_type)
149*890232f2SAndroid Build Coastguard Worker       : str_(str),
150*890232f2SAndroid Build Coastguard Worker         escape_char_('$'),
151*890232f2SAndroid Build Coastguard Worker         indent_(0),
152*890232f2SAndroid Build Coastguard Worker         indentation_size_(2),
153*890232f2SAndroid Build Coastguard Worker         indentation_type_(indentation_type) {}
154*890232f2SAndroid Build Coastguard Worker 
Print(const std::map<std::string,std::string> & vars,const char * string_template)155*890232f2SAndroid Build Coastguard Worker   void Print(const std::map<std::string, std::string> &vars,
156*890232f2SAndroid Build Coastguard Worker              const char *string_template) {
157*890232f2SAndroid Build Coastguard Worker     std::string s = string_template;
158*890232f2SAndroid Build Coastguard Worker     // Replace any occurrences of strings in "vars" that are surrounded
159*890232f2SAndroid Build Coastguard Worker     // by the escape character by what they're mapped to.
160*890232f2SAndroid Build Coastguard Worker     size_t pos;
161*890232f2SAndroid Build Coastguard Worker     while ((pos = s.find(escape_char_)) != std::string::npos) {
162*890232f2SAndroid Build Coastguard Worker       // Found an escape char, must also find the closing one.
163*890232f2SAndroid Build Coastguard Worker       size_t pos2 = s.find(escape_char_, pos + 1);
164*890232f2SAndroid Build Coastguard Worker       // If placeholder not closed, ignore.
165*890232f2SAndroid Build Coastguard Worker       if (pos2 == std::string::npos) break;
166*890232f2SAndroid Build Coastguard Worker       auto it = vars.find(s.substr(pos + 1, pos2 - pos - 1));
167*890232f2SAndroid Build Coastguard Worker       // If unknown placeholder, ignore.
168*890232f2SAndroid Build Coastguard Worker       if (it == vars.end()) break;
169*890232f2SAndroid Build Coastguard Worker       // Subtitute placeholder.
170*890232f2SAndroid Build Coastguard Worker       s.replace(pos, pos2 - pos + 1, it->second);
171*890232f2SAndroid Build Coastguard Worker     }
172*890232f2SAndroid Build Coastguard Worker     Print(s.c_str());
173*890232f2SAndroid Build Coastguard Worker   }
174*890232f2SAndroid Build Coastguard Worker 
Print(const char * s)175*890232f2SAndroid Build Coastguard Worker   void Print(const char *s) {
176*890232f2SAndroid Build Coastguard Worker     if (s == nullptr || *s == '\0') { return; }
177*890232f2SAndroid Build Coastguard Worker     // Add this string, but for each part separated by \n, add indentation.
178*890232f2SAndroid Build Coastguard Worker     for (;;) {
179*890232f2SAndroid Build Coastguard Worker       // Current indentation.
180*890232f2SAndroid Build Coastguard Worker       str_->insert(str_->end(), indent_ * indentation_size_, indentation_type_);
181*890232f2SAndroid Build Coastguard Worker       // See if this contains more than one line.
182*890232f2SAndroid Build Coastguard Worker       const char *lf = strchr(s, '\n');
183*890232f2SAndroid Build Coastguard Worker       if (lf) {
184*890232f2SAndroid Build Coastguard Worker         (*str_) += std::string(s, lf + 1);
185*890232f2SAndroid Build Coastguard Worker         s = lf + 1;
186*890232f2SAndroid Build Coastguard Worker         if (!*s) break;  // Only continue if there's more lines.
187*890232f2SAndroid Build Coastguard Worker       } else {
188*890232f2SAndroid Build Coastguard Worker         (*str_) += s;
189*890232f2SAndroid Build Coastguard Worker         break;
190*890232f2SAndroid Build Coastguard Worker       }
191*890232f2SAndroid Build Coastguard Worker     }
192*890232f2SAndroid Build Coastguard Worker   }
193*890232f2SAndroid Build Coastguard Worker 
SetIndentationSize(const size_t size)194*890232f2SAndroid Build Coastguard Worker   void SetIndentationSize(const size_t size) {
195*890232f2SAndroid Build Coastguard Worker     FLATBUFFERS_ASSERT(str_->empty());
196*890232f2SAndroid Build Coastguard Worker     indentation_size_ = size;
197*890232f2SAndroid Build Coastguard Worker   }
198*890232f2SAndroid Build Coastguard Worker 
Indent()199*890232f2SAndroid Build Coastguard Worker   void Indent() { indent_++; }
200*890232f2SAndroid Build Coastguard Worker 
Outdent()201*890232f2SAndroid Build Coastguard Worker   void Outdent() {
202*890232f2SAndroid Build Coastguard Worker     FLATBUFFERS_ASSERT(indent_ > 0);
203*890232f2SAndroid Build Coastguard Worker     indent_--;
204*890232f2SAndroid Build Coastguard Worker   }
205*890232f2SAndroid Build Coastguard Worker 
206*890232f2SAndroid Build Coastguard Worker  private:
207*890232f2SAndroid Build Coastguard Worker   std::string *str_;
208*890232f2SAndroid Build Coastguard Worker   char escape_char_;
209*890232f2SAndroid Build Coastguard Worker   size_t indent_;
210*890232f2SAndroid Build Coastguard Worker   size_t indentation_size_;
211*890232f2SAndroid Build Coastguard Worker   char indentation_type_;
212*890232f2SAndroid Build Coastguard Worker };
213*890232f2SAndroid Build Coastguard Worker 
214*890232f2SAndroid Build Coastguard Worker class FlatBufFile : public grpc_generator::File {
215*890232f2SAndroid Build Coastguard Worker  public:
216*890232f2SAndroid Build Coastguard Worker   enum Language {
217*890232f2SAndroid Build Coastguard Worker     kLanguageGo,
218*890232f2SAndroid Build Coastguard Worker     kLanguageCpp,
219*890232f2SAndroid Build Coastguard Worker     kLanguageJava,
220*890232f2SAndroid Build Coastguard Worker     kLanguagePython,
221*890232f2SAndroid Build Coastguard Worker     kLanguageSwift,
222*890232f2SAndroid Build Coastguard Worker     kLanguageTS
223*890232f2SAndroid Build Coastguard Worker   };
224*890232f2SAndroid Build Coastguard Worker 
FlatBufFile(const Parser & parser,const std::string & file_name,Language language)225*890232f2SAndroid Build Coastguard Worker   FlatBufFile(const Parser &parser, const std::string &file_name,
226*890232f2SAndroid Build Coastguard Worker               Language language)
227*890232f2SAndroid Build Coastguard Worker       : parser_(parser), file_name_(file_name), language_(language) {}
228*890232f2SAndroid Build Coastguard Worker 
229*890232f2SAndroid Build Coastguard Worker   FlatBufFile &operator=(const FlatBufFile &);
230*890232f2SAndroid Build Coastguard Worker 
GetLeadingComments(const grpc::string) const231*890232f2SAndroid Build Coastguard Worker   grpc::string GetLeadingComments(const grpc::string) const { return ""; }
232*890232f2SAndroid Build Coastguard Worker 
GetTrailingComments(const grpc::string) const233*890232f2SAndroid Build Coastguard Worker   grpc::string GetTrailingComments(const grpc::string) const { return ""; }
234*890232f2SAndroid Build Coastguard Worker 
GetAllComments() const235*890232f2SAndroid Build Coastguard Worker   std::vector<grpc::string> GetAllComments() const {
236*890232f2SAndroid Build Coastguard Worker     return std::vector<grpc::string>();
237*890232f2SAndroid Build Coastguard Worker   }
238*890232f2SAndroid Build Coastguard Worker 
filename() const239*890232f2SAndroid Build Coastguard Worker   std::string filename() const { return file_name_; }
240*890232f2SAndroid Build Coastguard Worker 
filename_without_ext() const241*890232f2SAndroid Build Coastguard Worker   std::string filename_without_ext() const {
242*890232f2SAndroid Build Coastguard Worker     return StripExtension(file_name_);
243*890232f2SAndroid Build Coastguard Worker   }
244*890232f2SAndroid Build Coastguard Worker 
package() const245*890232f2SAndroid Build Coastguard Worker   std::string package() const {
246*890232f2SAndroid Build Coastguard Worker     return parser_.current_namespace_->GetFullyQualifiedName("");
247*890232f2SAndroid Build Coastguard Worker   }
248*890232f2SAndroid Build Coastguard Worker 
package_parts() const249*890232f2SAndroid Build Coastguard Worker   std::vector<std::string> package_parts() const {
250*890232f2SAndroid Build Coastguard Worker     return parser_.current_namespace_->components;
251*890232f2SAndroid Build Coastguard Worker   }
252*890232f2SAndroid Build Coastguard Worker 
additional_headers() const253*890232f2SAndroid Build Coastguard Worker   std::string additional_headers() const {
254*890232f2SAndroid Build Coastguard Worker     switch (language_) {
255*890232f2SAndroid Build Coastguard Worker       case kLanguageCpp: {
256*890232f2SAndroid Build Coastguard Worker         return "#include \"flatbuffers/grpc.h\"\n";
257*890232f2SAndroid Build Coastguard Worker       }
258*890232f2SAndroid Build Coastguard Worker       case kLanguageGo: {
259*890232f2SAndroid Build Coastguard Worker         return "import \"github.com/google/flatbuffers/go\"";
260*890232f2SAndroid Build Coastguard Worker       }
261*890232f2SAndroid Build Coastguard Worker       case kLanguageJava: {
262*890232f2SAndroid Build Coastguard Worker         return "import com.google.flatbuffers.grpc.FlatbuffersUtils;";
263*890232f2SAndroid Build Coastguard Worker       }
264*890232f2SAndroid Build Coastguard Worker       case kLanguagePython: {
265*890232f2SAndroid Build Coastguard Worker         return "";
266*890232f2SAndroid Build Coastguard Worker       }
267*890232f2SAndroid Build Coastguard Worker       case kLanguageSwift: {
268*890232f2SAndroid Build Coastguard Worker         return "";
269*890232f2SAndroid Build Coastguard Worker       }
270*890232f2SAndroid Build Coastguard Worker       case kLanguageTS: {
271*890232f2SAndroid Build Coastguard Worker         return "";
272*890232f2SAndroid Build Coastguard Worker       }
273*890232f2SAndroid Build Coastguard Worker     }
274*890232f2SAndroid Build Coastguard Worker     return "";
275*890232f2SAndroid Build Coastguard Worker   }
276*890232f2SAndroid Build Coastguard Worker 
service_count() const277*890232f2SAndroid Build Coastguard Worker   int service_count() const {
278*890232f2SAndroid Build Coastguard Worker     return static_cast<int>(parser_.services_.vec.size());
279*890232f2SAndroid Build Coastguard Worker   }
280*890232f2SAndroid Build Coastguard Worker 
service(int i) const281*890232f2SAndroid Build Coastguard Worker   std::unique_ptr<const grpc_generator::Service> service(int i) const {
282*890232f2SAndroid Build Coastguard Worker     return std::unique_ptr<const grpc_generator::Service>(
283*890232f2SAndroid Build Coastguard Worker         new FlatBufService(parser_.services_.vec[i]));
284*890232f2SAndroid Build Coastguard Worker   }
285*890232f2SAndroid Build Coastguard Worker 
CreatePrinter(std::string * str,const char indentation_type=' ') const286*890232f2SAndroid Build Coastguard Worker   std::unique_ptr<grpc_generator::Printer> CreatePrinter(
287*890232f2SAndroid Build Coastguard Worker       std::string *str, const char indentation_type = ' ') const {
288*890232f2SAndroid Build Coastguard Worker     return std::unique_ptr<grpc_generator::Printer>(
289*890232f2SAndroid Build Coastguard Worker         new FlatBufPrinter(str, indentation_type));
290*890232f2SAndroid Build Coastguard Worker   }
291*890232f2SAndroid Build Coastguard Worker 
292*890232f2SAndroid Build Coastguard Worker  private:
293*890232f2SAndroid Build Coastguard Worker   const Parser &parser_;
294*890232f2SAndroid Build Coastguard Worker   const std::string &file_name_;
295*890232f2SAndroid Build Coastguard Worker   const Language language_;
296*890232f2SAndroid Build Coastguard Worker };
297*890232f2SAndroid Build Coastguard Worker 
298*890232f2SAndroid Build Coastguard Worker class GoGRPCGenerator : public flatbuffers::BaseGenerator {
299*890232f2SAndroid Build Coastguard Worker  public:
GoGRPCGenerator(const Parser & parser,const std::string & path,const std::string & file_name)300*890232f2SAndroid Build Coastguard Worker   GoGRPCGenerator(const Parser &parser, const std::string &path,
301*890232f2SAndroid Build Coastguard Worker                   const std::string &file_name)
302*890232f2SAndroid Build Coastguard Worker       : BaseGenerator(parser, path, file_name, "", "" /*Unused*/, "go"),
303*890232f2SAndroid Build Coastguard Worker         parser_(parser),
304*890232f2SAndroid Build Coastguard Worker         path_(path),
305*890232f2SAndroid Build Coastguard Worker         file_name_(file_name) {}
306*890232f2SAndroid Build Coastguard Worker 
generate()307*890232f2SAndroid Build Coastguard Worker   bool generate() {
308*890232f2SAndroid Build Coastguard Worker     FlatBufFile file(parser_, file_name_, FlatBufFile::kLanguageGo);
309*890232f2SAndroid Build Coastguard Worker     grpc_go_generator::Parameters p;
310*890232f2SAndroid Build Coastguard Worker     p.custom_method_io_type = "flatbuffers.Builder";
311*890232f2SAndroid Build Coastguard Worker     for (int i = 0; i < file.service_count(); i++) {
312*890232f2SAndroid Build Coastguard Worker       auto service = file.service(i);
313*890232f2SAndroid Build Coastguard Worker       const Definition *def = parser_.services_.vec[i];
314*890232f2SAndroid Build Coastguard Worker       p.package_name = LastNamespacePart(*(def->defined_namespace));
315*890232f2SAndroid Build Coastguard Worker       p.service_prefix =
316*890232f2SAndroid Build Coastguard Worker           def->defined_namespace->GetFullyQualifiedName("");  // file.package();
317*890232f2SAndroid Build Coastguard Worker       std::string output =
318*890232f2SAndroid Build Coastguard Worker           grpc_go_generator::GenerateServiceSource(&file, service.get(), &p);
319*890232f2SAndroid Build Coastguard Worker       std::string filename =
320*890232f2SAndroid Build Coastguard Worker           NamespaceDir(*def->defined_namespace) + def->name + "_grpc.go";
321*890232f2SAndroid Build Coastguard Worker       if (!flatbuffers::SaveFile(filename.c_str(), output, false)) return false;
322*890232f2SAndroid Build Coastguard Worker     }
323*890232f2SAndroid Build Coastguard Worker     return true;
324*890232f2SAndroid Build Coastguard Worker   }
325*890232f2SAndroid Build Coastguard Worker 
326*890232f2SAndroid Build Coastguard Worker  protected:
327*890232f2SAndroid Build Coastguard Worker   const Parser &parser_;
328*890232f2SAndroid Build Coastguard Worker   const std::string &path_, &file_name_;
329*890232f2SAndroid Build Coastguard Worker };
330*890232f2SAndroid Build Coastguard Worker 
GenerateGoGRPC(const Parser & parser,const std::string & path,const std::string & file_name)331*890232f2SAndroid Build Coastguard Worker bool GenerateGoGRPC(const Parser &parser, const std::string &path,
332*890232f2SAndroid Build Coastguard Worker                     const std::string &file_name) {
333*890232f2SAndroid Build Coastguard Worker   int nservices = 0;
334*890232f2SAndroid Build Coastguard Worker   for (auto it = parser.services_.vec.begin(); it != parser.services_.vec.end();
335*890232f2SAndroid Build Coastguard Worker        ++it) {
336*890232f2SAndroid Build Coastguard Worker     if (!(*it)->generated) nservices++;
337*890232f2SAndroid Build Coastguard Worker   }
338*890232f2SAndroid Build Coastguard Worker   if (!nservices) return true;
339*890232f2SAndroid Build Coastguard Worker   return GoGRPCGenerator(parser, path, file_name).generate();
340*890232f2SAndroid Build Coastguard Worker }
341*890232f2SAndroid Build Coastguard Worker 
GenerateCppGRPC(const Parser & parser,const std::string & path,const std::string & file_name)342*890232f2SAndroid Build Coastguard Worker bool GenerateCppGRPC(const Parser &parser, const std::string &path,
343*890232f2SAndroid Build Coastguard Worker                      const std::string &file_name) {
344*890232f2SAndroid Build Coastguard Worker   const auto &opts = parser.opts;
345*890232f2SAndroid Build Coastguard Worker   int nservices = 0;
346*890232f2SAndroid Build Coastguard Worker   for (auto it = parser.services_.vec.begin(); it != parser.services_.vec.end();
347*890232f2SAndroid Build Coastguard Worker        ++it) {
348*890232f2SAndroid Build Coastguard Worker     if (!(*it)->generated) nservices++;
349*890232f2SAndroid Build Coastguard Worker   }
350*890232f2SAndroid Build Coastguard Worker   if (!nservices) return true;
351*890232f2SAndroid Build Coastguard Worker 
352*890232f2SAndroid Build Coastguard Worker   std::string suffix = "";
353*890232f2SAndroid Build Coastguard Worker   suffix += opts.filename_suffix.empty() ? "_generated" : opts.filename_suffix;
354*890232f2SAndroid Build Coastguard Worker   suffix += ".";
355*890232f2SAndroid Build Coastguard Worker   suffix += opts.filename_extension.empty() ? "h" : opts.filename_extension;
356*890232f2SAndroid Build Coastguard Worker 
357*890232f2SAndroid Build Coastguard Worker   grpc_cpp_generator::Parameters generator_parameters;
358*890232f2SAndroid Build Coastguard Worker   // TODO(wvo): make the other parameters in this struct configurable.
359*890232f2SAndroid Build Coastguard Worker   generator_parameters.use_system_headers = true;
360*890232f2SAndroid Build Coastguard Worker   generator_parameters.message_header_extension = suffix;
361*890232f2SAndroid Build Coastguard Worker 
362*890232f2SAndroid Build Coastguard Worker   FlatBufFile fbfile(parser, file_name, FlatBufFile::kLanguageCpp);
363*890232f2SAndroid Build Coastguard Worker 
364*890232f2SAndroid Build Coastguard Worker   std::string header_code =
365*890232f2SAndroid Build Coastguard Worker       grpc_cpp_generator::GetHeaderPrologue(&fbfile, generator_parameters) +
366*890232f2SAndroid Build Coastguard Worker       grpc_cpp_generator::GetHeaderIncludes(&fbfile, generator_parameters) +
367*890232f2SAndroid Build Coastguard Worker       grpc_cpp_generator::GetHeaderServices(&fbfile, generator_parameters) +
368*890232f2SAndroid Build Coastguard Worker       grpc_cpp_generator::GetHeaderEpilogue(&fbfile, generator_parameters);
369*890232f2SAndroid Build Coastguard Worker 
370*890232f2SAndroid Build Coastguard Worker   std::string source_code =
371*890232f2SAndroid Build Coastguard Worker       grpc_cpp_generator::GetSourcePrologue(&fbfile, generator_parameters) +
372*890232f2SAndroid Build Coastguard Worker       grpc_cpp_generator::GetSourceIncludes(&fbfile, generator_parameters) +
373*890232f2SAndroid Build Coastguard Worker       grpc_cpp_generator::GetSourceServices(&fbfile, generator_parameters) +
374*890232f2SAndroid Build Coastguard Worker       grpc_cpp_generator::GetSourceEpilogue(&fbfile, generator_parameters);
375*890232f2SAndroid Build Coastguard Worker 
376*890232f2SAndroid Build Coastguard Worker   return flatbuffers::SaveFile((path + file_name + ".grpc.fb.h").c_str(),
377*890232f2SAndroid Build Coastguard Worker                                header_code, false) &&
378*890232f2SAndroid Build Coastguard Worker          flatbuffers::SaveFile((path + file_name + ".grpc.fb.cc").c_str(),
379*890232f2SAndroid Build Coastguard Worker                                source_code, false);
380*890232f2SAndroid Build Coastguard Worker }
381*890232f2SAndroid Build Coastguard Worker 
382*890232f2SAndroid Build Coastguard Worker class JavaGRPCGenerator : public flatbuffers::BaseGenerator {
383*890232f2SAndroid Build Coastguard Worker  public:
JavaGRPCGenerator(const Parser & parser,const std::string & path,const std::string & file_name)384*890232f2SAndroid Build Coastguard Worker   JavaGRPCGenerator(const Parser &parser, const std::string &path,
385*890232f2SAndroid Build Coastguard Worker                     const std::string &file_name)
386*890232f2SAndroid Build Coastguard Worker       : BaseGenerator(parser, path, file_name, "", "." /*separator*/, "java") {}
387*890232f2SAndroid Build Coastguard Worker 
generate()388*890232f2SAndroid Build Coastguard Worker   bool generate() {
389*890232f2SAndroid Build Coastguard Worker     FlatBufFile file(parser_, file_name_, FlatBufFile::kLanguageJava);
390*890232f2SAndroid Build Coastguard Worker     grpc_java_generator::Parameters p;
391*890232f2SAndroid Build Coastguard Worker     for (int i = 0; i < file.service_count(); i++) {
392*890232f2SAndroid Build Coastguard Worker       auto service = file.service(i);
393*890232f2SAndroid Build Coastguard Worker       const Definition *def = parser_.services_.vec[i];
394*890232f2SAndroid Build Coastguard Worker       p.package_name =
395*890232f2SAndroid Build Coastguard Worker           def->defined_namespace->GetFullyQualifiedName("");  // file.package();
396*890232f2SAndroid Build Coastguard Worker       std::string output =
397*890232f2SAndroid Build Coastguard Worker           grpc_java_generator::GenerateServiceSource(&file, service.get(), &p);
398*890232f2SAndroid Build Coastguard Worker       std::string filename =
399*890232f2SAndroid Build Coastguard Worker           NamespaceDir(*def->defined_namespace) + def->name + "Grpc.java";
400*890232f2SAndroid Build Coastguard Worker       if (!flatbuffers::SaveFile(filename.c_str(), output, false)) return false;
401*890232f2SAndroid Build Coastguard Worker     }
402*890232f2SAndroid Build Coastguard Worker     return true;
403*890232f2SAndroid Build Coastguard Worker   }
404*890232f2SAndroid Build Coastguard Worker };
405*890232f2SAndroid Build Coastguard Worker 
GenerateJavaGRPC(const Parser & parser,const std::string & path,const std::string & file_name)406*890232f2SAndroid Build Coastguard Worker bool GenerateJavaGRPC(const Parser &parser, const std::string &path,
407*890232f2SAndroid Build Coastguard Worker                       const std::string &file_name) {
408*890232f2SAndroid Build Coastguard Worker   int nservices = 0;
409*890232f2SAndroid Build Coastguard Worker   for (auto it = parser.services_.vec.begin(); it != parser.services_.vec.end();
410*890232f2SAndroid Build Coastguard Worker        ++it) {
411*890232f2SAndroid Build Coastguard Worker     if (!(*it)->generated) nservices++;
412*890232f2SAndroid Build Coastguard Worker   }
413*890232f2SAndroid Build Coastguard Worker   if (!nservices) return true;
414*890232f2SAndroid Build Coastguard Worker   return JavaGRPCGenerator(parser, path, file_name).generate();
415*890232f2SAndroid Build Coastguard Worker }
416*890232f2SAndroid Build Coastguard Worker 
417*890232f2SAndroid Build Coastguard Worker class PythonGRPCGenerator : public flatbuffers::BaseGenerator {
418*890232f2SAndroid Build Coastguard Worker  private:
419*890232f2SAndroid Build Coastguard Worker   CodeWriter code_;
420*890232f2SAndroid Build Coastguard Worker 
421*890232f2SAndroid Build Coastguard Worker  public:
PythonGRPCGenerator(const Parser & parser,const std::string & filename)422*890232f2SAndroid Build Coastguard Worker   PythonGRPCGenerator(const Parser &parser, const std::string &filename)
423*890232f2SAndroid Build Coastguard Worker       : BaseGenerator(parser, "", filename, "", "" /*Unused*/, "swift") {}
424*890232f2SAndroid Build Coastguard Worker 
generate()425*890232f2SAndroid Build Coastguard Worker   bool generate() {
426*890232f2SAndroid Build Coastguard Worker     code_.Clear();
427*890232f2SAndroid Build Coastguard Worker     code_ +=
428*890232f2SAndroid Build Coastguard Worker         "# Generated by the gRPC Python protocol compiler plugin. "
429*890232f2SAndroid Build Coastguard Worker         "DO NOT EDIT!\n";
430*890232f2SAndroid Build Coastguard Worker     code_ += "import grpc\n";
431*890232f2SAndroid Build Coastguard Worker 
432*890232f2SAndroid Build Coastguard Worker     FlatBufFile file(parser_, file_name_, FlatBufFile::kLanguagePython);
433*890232f2SAndroid Build Coastguard Worker 
434*890232f2SAndroid Build Coastguard Worker     for (int i = 0; i < file.service_count(); i++) {
435*890232f2SAndroid Build Coastguard Worker       auto service = file.service(i);
436*890232f2SAndroid Build Coastguard Worker       code_ += grpc_python_generator::Generate(&file, service.get());
437*890232f2SAndroid Build Coastguard Worker     }
438*890232f2SAndroid Build Coastguard Worker     const auto final_code = code_.ToString();
439*890232f2SAndroid Build Coastguard Worker     const auto filename = GenerateFileName();
440*890232f2SAndroid Build Coastguard Worker     return SaveFile(filename.c_str(), final_code, false);
441*890232f2SAndroid Build Coastguard Worker   }
442*890232f2SAndroid Build Coastguard Worker 
GenerateFileName()443*890232f2SAndroid Build Coastguard Worker   std::string GenerateFileName() {
444*890232f2SAndroid Build Coastguard Worker     std::string namespace_dir;
445*890232f2SAndroid Build Coastguard Worker     auto &namespaces = parser_.namespaces_.back()->components;
446*890232f2SAndroid Build Coastguard Worker     for (auto it = namespaces.begin(); it != namespaces.end(); ++it) {
447*890232f2SAndroid Build Coastguard Worker       if (it != namespaces.begin()) namespace_dir += kPathSeparator;
448*890232f2SAndroid Build Coastguard Worker       namespace_dir += *it;
449*890232f2SAndroid Build Coastguard Worker     }
450*890232f2SAndroid Build Coastguard Worker     std::string grpc_py_filename = namespace_dir;
451*890232f2SAndroid Build Coastguard Worker     if (!namespace_dir.empty()) grpc_py_filename += kPathSeparator;
452*890232f2SAndroid Build Coastguard Worker     return grpc_py_filename + file_name_ + "_grpc_fb.py";
453*890232f2SAndroid Build Coastguard Worker   }
454*890232f2SAndroid Build Coastguard Worker };
455*890232f2SAndroid Build Coastguard Worker 
GeneratePythonGRPC(const Parser & parser,const std::string &,const std::string & file_name)456*890232f2SAndroid Build Coastguard Worker bool GeneratePythonGRPC(const Parser &parser, const std::string & /*path*/,
457*890232f2SAndroid Build Coastguard Worker                         const std::string &file_name) {
458*890232f2SAndroid Build Coastguard Worker   int nservices = 0;
459*890232f2SAndroid Build Coastguard Worker   for (auto it = parser.services_.vec.begin(); it != parser.services_.vec.end();
460*890232f2SAndroid Build Coastguard Worker        ++it) {
461*890232f2SAndroid Build Coastguard Worker     if (!(*it)->generated) nservices++;
462*890232f2SAndroid Build Coastguard Worker   }
463*890232f2SAndroid Build Coastguard Worker   if (!nservices) return true;
464*890232f2SAndroid Build Coastguard Worker 
465*890232f2SAndroid Build Coastguard Worker   return PythonGRPCGenerator(parser, file_name).generate();
466*890232f2SAndroid Build Coastguard Worker }
467*890232f2SAndroid Build Coastguard Worker 
468*890232f2SAndroid Build Coastguard Worker class SwiftGRPCGenerator : public flatbuffers::BaseGenerator {
469*890232f2SAndroid Build Coastguard Worker  private:
470*890232f2SAndroid Build Coastguard Worker   CodeWriter code_;
471*890232f2SAndroid Build Coastguard Worker 
472*890232f2SAndroid Build Coastguard Worker  public:
SwiftGRPCGenerator(const Parser & parser,const std::string & path,const std::string & filename)473*890232f2SAndroid Build Coastguard Worker   SwiftGRPCGenerator(const Parser &parser, const std::string &path,
474*890232f2SAndroid Build Coastguard Worker                      const std::string &filename)
475*890232f2SAndroid Build Coastguard Worker       : BaseGenerator(parser, path, filename, "", "" /*Unused*/, "swift") {}
476*890232f2SAndroid Build Coastguard Worker 
generate()477*890232f2SAndroid Build Coastguard Worker   bool generate() {
478*890232f2SAndroid Build Coastguard Worker     code_.Clear();
479*890232f2SAndroid Build Coastguard Worker     code_ += "// Generated GRPC code for FlatBuffers swift!";
480*890232f2SAndroid Build Coastguard Worker     code_ += grpc_swift_generator::GenerateHeader();
481*890232f2SAndroid Build Coastguard Worker     FlatBufFile file(parser_, file_name_, FlatBufFile::kLanguageSwift);
482*890232f2SAndroid Build Coastguard Worker     for (int i = 0; i < file.service_count(); i++) {
483*890232f2SAndroid Build Coastguard Worker       auto service = file.service(i);
484*890232f2SAndroid Build Coastguard Worker       code_ += grpc_swift_generator::Generate(&file, service.get());
485*890232f2SAndroid Build Coastguard Worker     }
486*890232f2SAndroid Build Coastguard Worker     const auto final_code = code_.ToString();
487*890232f2SAndroid Build Coastguard Worker     const auto filename = GeneratedFileName(path_, file_name_);
488*890232f2SAndroid Build Coastguard Worker     return SaveFile(filename.c_str(), final_code, false);
489*890232f2SAndroid Build Coastguard Worker   }
490*890232f2SAndroid Build Coastguard Worker 
GeneratedFileName(const std::string & path,const std::string & file_name)491*890232f2SAndroid Build Coastguard Worker   static std::string GeneratedFileName(const std::string &path,
492*890232f2SAndroid Build Coastguard Worker                                        const std::string &file_name) {
493*890232f2SAndroid Build Coastguard Worker     return path + file_name + ".grpc.swift";
494*890232f2SAndroid Build Coastguard Worker   }
495*890232f2SAndroid Build Coastguard Worker };
496*890232f2SAndroid Build Coastguard Worker 
GenerateSwiftGRPC(const Parser & parser,const std::string & path,const std::string & file_name)497*890232f2SAndroid Build Coastguard Worker bool GenerateSwiftGRPC(const Parser &parser, const std::string &path,
498*890232f2SAndroid Build Coastguard Worker                        const std::string &file_name) {
499*890232f2SAndroid Build Coastguard Worker   int nservices = 0;
500*890232f2SAndroid Build Coastguard Worker   for (auto it = parser.services_.vec.begin(); it != parser.services_.vec.end();
501*890232f2SAndroid Build Coastguard Worker        ++it) {
502*890232f2SAndroid Build Coastguard Worker     if (!(*it)->generated) nservices++;
503*890232f2SAndroid Build Coastguard Worker   }
504*890232f2SAndroid Build Coastguard Worker   if (!nservices) return true;
505*890232f2SAndroid Build Coastguard Worker   return SwiftGRPCGenerator(parser, path, file_name).generate();
506*890232f2SAndroid Build Coastguard Worker }
507*890232f2SAndroid Build Coastguard Worker 
508*890232f2SAndroid Build Coastguard Worker class TSGRPCGenerator : public flatbuffers::BaseGenerator {
509*890232f2SAndroid Build Coastguard Worker  private:
510*890232f2SAndroid Build Coastguard Worker   CodeWriter code_;
511*890232f2SAndroid Build Coastguard Worker 
512*890232f2SAndroid Build Coastguard Worker  public:
TSGRPCGenerator(const Parser & parser,const std::string & path,const std::string & filename)513*890232f2SAndroid Build Coastguard Worker   TSGRPCGenerator(const Parser &parser, const std::string &path,
514*890232f2SAndroid Build Coastguard Worker                   const std::string &filename)
515*890232f2SAndroid Build Coastguard Worker       : BaseGenerator(parser, path, filename, "", "" /*Unused*/, "ts") {}
516*890232f2SAndroid Build Coastguard Worker 
generate()517*890232f2SAndroid Build Coastguard Worker   bool generate() {
518*890232f2SAndroid Build Coastguard Worker     code_.Clear();
519*890232f2SAndroid Build Coastguard Worker     FlatBufFile file(parser_, file_name_, FlatBufFile::kLanguageTS);
520*890232f2SAndroid Build Coastguard Worker 
521*890232f2SAndroid Build Coastguard Worker     for (int i = 0; i < file.service_count(); i++) {
522*890232f2SAndroid Build Coastguard Worker       auto service = file.service(i);
523*890232f2SAndroid Build Coastguard Worker       code_ += grpc_ts_generator::Generate(&file, service.get(), file_name_);
524*890232f2SAndroid Build Coastguard Worker       const auto ts_name = GeneratedFileName(path_, file_name_);
525*890232f2SAndroid Build Coastguard Worker       if (!SaveFile(ts_name.c_str(), code_.ToString(), false)) return false;
526*890232f2SAndroid Build Coastguard Worker 
527*890232f2SAndroid Build Coastguard Worker       code_.Clear();
528*890232f2SAndroid Build Coastguard Worker       code_ += grpc_ts_generator::GenerateInterface(&file, service.get(),
529*890232f2SAndroid Build Coastguard Worker                                                     file_name_);
530*890232f2SAndroid Build Coastguard Worker       const auto ts_interface_name = GeneratedFileName(path_, file_name_, true);
531*890232f2SAndroid Build Coastguard Worker       if (!SaveFile(ts_interface_name.c_str(), code_.ToString(), false))
532*890232f2SAndroid Build Coastguard Worker         return false;
533*890232f2SAndroid Build Coastguard Worker     }
534*890232f2SAndroid Build Coastguard Worker     return true;
535*890232f2SAndroid Build Coastguard Worker   }
536*890232f2SAndroid Build Coastguard Worker 
GeneratedFileName(const std::string & path,const std::string & file_name,const bool is_interface=false)537*890232f2SAndroid Build Coastguard Worker   static std::string GeneratedFileName(const std::string &path,
538*890232f2SAndroid Build Coastguard Worker                                        const std::string &file_name,
539*890232f2SAndroid Build Coastguard Worker                                        const bool is_interface = false) {
540*890232f2SAndroid Build Coastguard Worker     if (is_interface) return path + file_name + "_grpc.d.ts";
541*890232f2SAndroid Build Coastguard Worker     return path + file_name + "_grpc.js";
542*890232f2SAndroid Build Coastguard Worker   }
543*890232f2SAndroid Build Coastguard Worker };
544*890232f2SAndroid Build Coastguard Worker 
GenerateTSGRPC(const Parser & parser,const std::string & path,const std::string & file_name)545*890232f2SAndroid Build Coastguard Worker bool GenerateTSGRPC(const Parser &parser, const std::string &path,
546*890232f2SAndroid Build Coastguard Worker                     const std::string &file_name) {
547*890232f2SAndroid Build Coastguard Worker   int nservices = 0;
548*890232f2SAndroid Build Coastguard Worker   for (auto it = parser.services_.vec.begin(); it != parser.services_.vec.end();
549*890232f2SAndroid Build Coastguard Worker        ++it) {
550*890232f2SAndroid Build Coastguard Worker     if (!(*it)->generated) nservices++;
551*890232f2SAndroid Build Coastguard Worker   }
552*890232f2SAndroid Build Coastguard Worker   if (!nservices) return true;
553*890232f2SAndroid Build Coastguard Worker   return TSGRPCGenerator(parser, path, file_name).generate();
554*890232f2SAndroid Build Coastguard Worker }
555*890232f2SAndroid Build Coastguard Worker 
556*890232f2SAndroid Build Coastguard Worker }  // namespace flatbuffers
557*890232f2SAndroid Build Coastguard Worker 
558*890232f2SAndroid Build Coastguard Worker #if defined(_MSC_VER)
559*890232f2SAndroid Build Coastguard Worker #  pragma warning(pop)
560*890232f2SAndroid Build Coastguard Worker #endif
561