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 namespace flatbuffers {
     28 
     29 class FlatBufMethod : public grpc_generator::Method {
     30  public:
     31   enum Streaming { kNone, kClient, kServer, kBiDi };
     32 
     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 
     44   std::string name() const { return method_->name; }
     45 
     46   std::string GRPCType(const StructDef &sd) const {
     47     return "flatbuffers::BufferRef<" + sd.name + ">";
     48   }
     49 
     50   std::string input_type_name() const {
     51     return GRPCType(*method_->request);
     52   }
     53   std::string output_type_name() const {
     54     return GRPCType(*method_->response);
     55   }
     56 
     57   std::string input_name() const {
     58     return (*method_->request).name;
     59   }
     60 
     61   std::string output_name() const {
     62     return (*method_->response).name;
     63   }
     64 
     65   bool NoStreaming() const { return streaming_ == kNone; }
     66   bool ClientOnlyStreaming() const { return streaming_ == kClient; }
     67   bool ServerOnlyStreaming() const { return streaming_ == kServer; }
     68   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:
     77   FlatBufService(const ServiceDef *service) : service_(service) {}
     78 
     79   std::string name() const { return service_->name; }
     80 
     81   int method_count() const {
     82     return static_cast<int>(service_->calls.vec.size());
     83   };
     84 
     85   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:
     96   FlatBufPrinter(std::string *str)
     97     : str_(str), escape_char_('$'), indent_(0) {}
     98 
     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 
    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 
    137   void Indent() { indent_++; }
    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:
    148   FlatBufFile(const Parser &parser, const std::string &file_name)
    149     : parser_(parser), file_name_(file_name) {}
    150   FlatBufFile &operator=(const FlatBufFile &);
    151 
    152   std::string filename() const { return file_name_; }
    153   std::string filename_without_ext() const {
    154     return StripExtension(file_name_);
    155   }
    156 
    157   std::string message_header_ext() const { return "_generated.h"; }
    158   std::string service_header_ext() const { return ".grpc.fb.h"; }
    159 
    160   std::string package() const {
    161     return parser_.namespaces_.back()->GetFullyQualifiedName("");
    162   }
    163 
    164   std::vector<std::string> package_parts() const {
    165     return parser_.namespaces_.back()->components;
    166   }
    167 
    168   std::string additional_headers() const {
    169     return "#include \"flatbuffers/grpc.h\"\n";
    170   }
    171 
    172   std::string additional_imports() const {
    173     return "import \"github.com/google/flatbuffers/go\"";
    174   }
    175 
    176   int service_count() const {
    177     return static_cast<int>(parser_.services_.vec.size());
    178   };
    179 
    180   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 
    185   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:
    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 
    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 
    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 
    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