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