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