blob: e01b496ed69b3594cdce6766cdf48b02422ccf1d [file] [log] [blame]
nnobleebebb7e2014-12-10 16:31:01 -08001/*
2 *
3 * Copyright 2014, Google Inc.
4 * All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions are
8 * met:
9 *
10 * * Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * * Redistributions in binary form must reproduce the above
13 * copyright notice, this list of conditions and the following disclaimer
14 * in the documentation and/or other materials provided with the
15 * distribution.
16 * * Neither the name of Google Inc. nor the names of its
17 * contributors may be used to endorse or promote products derived from
18 * this software without specific prior written permission.
19 *
20 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
23 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
24 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
25 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
26 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
30 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31 *
32 */
33
34#include "src/compiler/cpp_generator.h"
35
36#include "src/compiler/cpp_generator_helpers.h"
37#include <google/protobuf/descriptor.h>
38#include <google/protobuf/descriptor.pb.h>
39#include <google/protobuf/io/printer.h>
40#include <google/protobuf/io/zero_copy_stream_impl_lite.h>
41
42namespace grpc_cpp_generator {
43namespace {
44
45bool NoStreaming(const google::protobuf::MethodDescriptor* method) {
rocking718c3f72014-12-11 13:41:17 -080046 return !method->client_streaming() &&
47 !method->server_streaming();
nnobleebebb7e2014-12-10 16:31:01 -080048}
49
50bool ClientOnlyStreaming(const google::protobuf::MethodDescriptor* method) {
rocking718c3f72014-12-11 13:41:17 -080051 return method->client_streaming() &&
52 !method->server_streaming();
nnobleebebb7e2014-12-10 16:31:01 -080053}
54
55bool ServerOnlyStreaming(const google::protobuf::MethodDescriptor* method) {
rocking718c3f72014-12-11 13:41:17 -080056 return !method->client_streaming() &&
57 method->server_streaming();
nnobleebebb7e2014-12-10 16:31:01 -080058}
59
60bool BidiStreaming(const google::protobuf::MethodDescriptor* method) {
rocking718c3f72014-12-11 13:41:17 -080061 return method->client_streaming() &&
62 method->server_streaming();
nnobleebebb7e2014-12-10 16:31:01 -080063}
64
65bool HasClientOnlyStreaming(const google::protobuf::FileDescriptor* file) {
66 for (int i = 0; i < file->service_count(); i++) {
67 for (int j = 0; j < file->service(i)->method_count(); j++) {
68 if (ClientOnlyStreaming(file->service(i)->method(j))) {
69 return true;
70 }
71 }
72 }
73 return false;
74}
75
76bool HasServerOnlyStreaming(const google::protobuf::FileDescriptor* file) {
77 for (int i = 0; i < file->service_count(); i++) {
78 for (int j = 0; j < file->service(i)->method_count(); j++) {
79 if (ServerOnlyStreaming(file->service(i)->method(j))) {
80 return true;
81 }
82 }
83 }
84 return false;
85}
86
87bool HasBidiStreaming(const google::protobuf::FileDescriptor* file) {
88 for (int i = 0; i < file->service_count(); i++) {
89 for (int j = 0; j < file->service(i)->method_count(); j++) {
90 if (BidiStreaming(file->service(i)->method(j))) {
91 return true;
92 }
93 }
94 }
95 return false;
96}
97} // namespace
98
99string GetHeaderIncludes(const google::protobuf::FileDescriptor* file) {
100 string temp =
101 "#include \"net/grpc/cpp/internal/client/internal_stub.h\"\n"
102 "#include \"net/grpc/cpp/public/status.h\"\n"
103 "\n"
104 "namespace grpc {\n"
105 "class ChannelInterface;\n"
106 "class RpcService;\n";
107 if (HasClientOnlyStreaming(file)) {
108 temp.append("template <class OutMessage> class ClientWriter;\n");
109 temp.append("template <class InMessage> class ServerReader;\n");
110 }
111 if (HasServerOnlyStreaming(file)) {
112 temp.append("template <class InMessage> class ClientReader;\n");
113 temp.append("template <class OutMessage> class ServerWriter;\n");
114 }
115 if (HasBidiStreaming(file)) {
116 temp.append(
117 "template <class OutMessage, class InMessage>\n"
118 "class ClientReaderWriter;\n");
119 temp.append(
120 "template <class OutMessage, class InMessage>\n"
121 "class ServerReaderWriter;\n");
122 }
123 temp.append("} // namespace grpc\n");
124 return temp;
125}
126
127string GetSourceIncludes() {
128 return "#include \"net/grpc/cpp/internal/rpc_method.h\"\n"
129 "#include \"net/grpc/cpp/internal/server/rpc_service_method.h\"\n"
130 "#include \"net/grpc/cpp/public/channel_interface.h\"\n"
131 "#include \"net/grpc/cpp/public/stream.h\"\n";
132}
133
134void PrintHeaderClientMethod(google::protobuf::io::Printer* printer,
135 const google::protobuf::MethodDescriptor* method,
136 map<string, string>* vars) {
137 (*vars)["Method"] = method->name();
138 (*vars)["Request"] =
139 grpc_cpp_generator::ClassName(method->input_type(), true);
140 (*vars)["Response"] =
141 grpc_cpp_generator::ClassName(method->output_type(), true);
142 if (NoStreaming(method)) {
143 printer->Print(*vars,
144 "::grpc::Status $Method$(::grpc::ClientContext* context, "
145 "const $Request$& request, $Response$* response);\n\n");
146 } else if (ClientOnlyStreaming(method)) {
147 printer->Print(
148 *vars,
149 "::grpc::ClientWriter<$Request$>* $Method$("
150 "::grpc::ClientContext* context, $Response$* response);\n\n");
151 } else if (ServerOnlyStreaming(method)) {
152 printer->Print(
153 *vars,
154 "::grpc::ClientReader<$Response$>* $Method$("
155 "::grpc::ClientContext* context, const $Request$* request);\n\n");
156 } else if (BidiStreaming(method)) {
157 printer->Print(*vars,
158 "::grpc::ClientReaderWriter<$Request$, $Response$>* "
159 "$Method$(::grpc::ClientContext* context);\n\n");
160 }
161}
162
163void PrintHeaderServerMethod(google::protobuf::io::Printer* printer,
164 const google::protobuf::MethodDescriptor* method,
165 map<string, string>* vars) {
166 (*vars)["Method"] = method->name();
167 (*vars)["Request"] =
168 grpc_cpp_generator::ClassName(method->input_type(), true);
169 (*vars)["Response"] =
170 grpc_cpp_generator::ClassName(method->output_type(), true);
171 if (NoStreaming(method)) {
172 printer->Print(*vars,
173 "virtual ::grpc::Status $Method$(const $Request$* request, "
174 "$Response$* response);\n");
175 } else if (ClientOnlyStreaming(method)) {
176 printer->Print(*vars,
177 "virtual ::grpc::Status $Method$("
178 "::grpc::ServerReader<$Request$>* reader, "
179 "$Response$* response);\n");
180 } else if (ServerOnlyStreaming(method)) {
181 printer->Print(*vars,
182 "virtual ::grpc::Status $Method$(const $Request$* request, "
183 "::grpc::ServerWriter<$Response$>* writer);\n");
184 } else if (BidiStreaming(method)) {
185 printer->Print(*vars,
186 "virtual ::grpc::Status $Method$("
187 "::grpc::ServerReaderWriter<$Response$, $Request$>* stream);"
188 "\n");
189 }
190}
191
192void PrintHeaderService(google::protobuf::io::Printer* printer,
193 const google::protobuf::ServiceDescriptor* service,
194 map<string, string>* vars) {
195 (*vars)["Service"] = service->name();
196
197 printer->Print(*vars,
198 "class $Service$ {\n"
199 " public:\n");
200 printer->Indent();
201
202 // Client side
203 printer->Print("class Stub : public ::grpc::InternalStub {\n"
204 " public:\n");
205 printer->Indent();
206 for (int i = 0; i < service->method_count(); ++i) {
207 PrintHeaderClientMethod(printer, service->method(i), vars);
208 }
209 printer->Outdent();
210 printer->Print("};\n");
211 printer->Print(
212 "static Stub* NewStub(const std::shared_ptr<::grpc::ChannelInterface>& "
213 "channel);\n");
214
215 printer->Print("\n");
216
217 // Server side
218 printer->Print("class Service {\n"
219 " public:\n");
220 printer->Indent();
221 printer->Print("Service() : service_(nullptr) {}\n");
222 printer->Print("virtual ~Service();\n");
223 for (int i = 0; i < service->method_count(); ++i) {
224 PrintHeaderServerMethod(printer, service->method(i), vars);
225 }
226 printer->Print("::grpc::RpcService* service();\n");
227 printer->Outdent();
228 printer->Print(" private:\n"
229 " ::grpc::RpcService* service_;\n");
230 printer->Print("};\n");
231
232 printer->Outdent();
233 printer->Print("};\n");
234}
235
236string GetHeaderServices(const google::protobuf::FileDescriptor* file) {
237 string output;
238 google::protobuf::io::StringOutputStream output_stream(&output);
239 google::protobuf::io::Printer printer(&output_stream, '$');
240 map<string, string> vars;
241
242 for (int i = 0; i < file->service_count(); ++i) {
243 PrintHeaderService(&printer, file->service(0), &vars);
244 printer.Print("\n");
245 }
246 return output;
247}
248
249void PrintSourceClientMethod(google::protobuf::io::Printer* printer,
250 const google::protobuf::MethodDescriptor* method,
251 map<string, string>* vars) {
252 (*vars)["Method"] = method->name();
253 (*vars)["Request"] =
254 grpc_cpp_generator::ClassName(method->input_type(), true);
255 (*vars)["Response"] =
256 grpc_cpp_generator::ClassName(method->output_type(), true);
257 if (NoStreaming(method)) {
258 printer->Print(*vars,
259 "::grpc::Status $Service$::Stub::$Method$("
260 "::grpc::ClientContext* context, "
261 "const $Request$& request, $Response$* response) {\n");
262 printer->Print(*vars,
263 " return channel()->StartBlockingRpc("
264 "::grpc::RpcMethod(\"/$Service$/$Method$\"), "
265 "context, request, response);\n"
266 "}\n\n");
267 } else if (ClientOnlyStreaming(method)) {
268 printer->Print(*vars,
269 "::grpc::ClientWriter<$Request$>* $Service$::Stub::$Method$("
270 "::grpc::ClientContext* context, $Response$* response) {\n");
271 printer->Print(
272 *vars,
273 " return new ::grpc::ClientWriter<$Request$>("
274 "channel()->CreateStream(::grpc::RpcMethod(\"/$Service$/$Method$\", "
275 "::grpc::RpcMethod::RpcType::CLIENT_STREAMING), "
276 "context, nullptr, response));\n"
277 "}\n\n");
278 } else if (ServerOnlyStreaming(method)) {
279 printer->Print(
280 *vars,
281 "::grpc::ClientReader<$Response$>* $Service$::Stub::$Method$("
282 "::grpc::ClientContext* context, const $Request$* request) {\n");
283 printer->Print(
284 *vars,
285 " return new ::grpc::ClientReader<$Response$>("
286 "channel()->CreateStream(::grpc::RpcMethod(\"/$Service$/$Method$\", "
287 "::grpc::RpcMethod::RpcType::SERVER_STREAMING), "
288 "context, request, nullptr));\n"
289 "}\n\n");
290 } else if (BidiStreaming(method)) {
291 printer->Print(
292 *vars,
293 "::grpc::ClientReaderWriter<$Request$, $Response$>* "
294 "$Service$::Stub::$Method$(::grpc::ClientContext* context) {\n");
295 printer->Print(
296 *vars,
297 " return new ::grpc::ClientReaderWriter<$Request$, $Response$>("
298 "channel()->CreateStream(::grpc::RpcMethod(\"/$Service$/$Method$\", "
299 "::grpc::RpcMethod::RpcType::BIDI_STREAMING), "
300 "context, nullptr, nullptr));\n"
301 "}\n\n");
302 }
303}
304
305void PrintSourceServerMethod(google::protobuf::io::Printer* printer,
306 const google::protobuf::MethodDescriptor* method,
307 map<string, string>* vars) {
308 (*vars)["Method"] = method->name();
309 (*vars)["Request"] =
310 grpc_cpp_generator::ClassName(method->input_type(), true);
311 (*vars)["Response"] =
312 grpc_cpp_generator::ClassName(method->output_type(), true);
313 if (NoStreaming(method)) {
314 printer->Print(*vars,
315 "::grpc::Status $Service$::Service::$Method$("
316 "const $Request$* request, $Response$* response) {\n");
317 printer->Print(
318 " return ::grpc::Status("
319 "::grpc::StatusCode::UNIMPLEMENTED);\n");
320 printer->Print("}\n\n");
321 } else if (ClientOnlyStreaming(method)) {
322 printer->Print(*vars,
323 "::grpc::Status $Service$::Service::$Method$("
324 "::grpc::ServerReader<$Request$>* reader, "
325 "$Response$* response) {\n");
326 printer->Print(
327 " return ::grpc::Status("
328 "::grpc::StatusCode::UNIMPLEMENTED);\n");
329 printer->Print("}\n\n");
330 } else if (ServerOnlyStreaming(method)) {
331 printer->Print(*vars,
332 "::grpc::Status $Service$::Service::$Method$("
333 "const $Request$* request, "
334 "::grpc::ServerWriter<$Response$>* writer) {\n");
335 printer->Print(
336 " return ::grpc::Status("
337 "::grpc::StatusCode::UNIMPLEMENTED);\n");
338 printer->Print("}\n\n");
339 } else if (BidiStreaming(method)) {
340 printer->Print(*vars,
341 "::grpc::Status $Service$::Service::$Method$("
342 "::grpc::ServerReaderWriter<$Response$, $Request$>* "
343 "stream) {\n");
344 printer->Print(
345 " return ::grpc::Status("
346 "::grpc::StatusCode::UNIMPLEMENTED);\n");
347 printer->Print("}\n\n");
348 }
349}
350
351void PrintSourceService(google::protobuf::io::Printer* printer,
352 const google::protobuf::ServiceDescriptor* service,
353 map<string, string>* vars) {
354 (*vars)["Service"] = service->name();
355 printer->Print(*vars,
356 "$Service$::Stub* $Service$::NewStub("
357 "const std::shared_ptr<::grpc::ChannelInterface>& channel) {\n"
358 " $Service$::Stub* stub = new $Service$::Stub();\n"
359 " stub->set_channel(channel);\n"
360 " return stub;\n"
361 "};\n\n");
362 for (int i = 0; i < service->method_count(); ++i) {
363 PrintSourceClientMethod(printer, service->method(i), vars);
364 }
365
366 printer->Print(*vars,
367 "$Service$::Service::~Service() {\n"
368 " delete service_;\n"
369 "}\n\n");
370 for (int i = 0; i < service->method_count(); ++i) {
371 PrintSourceServerMethod(printer, service->method(i), vars);
372 }
373 printer->Print(*vars,
374 "::grpc::RpcService* $Service$::Service::service() {\n");
375 printer->Indent();
376 printer->Print("if (service_ != nullptr) {\n"
377 " return service_;\n"
378 "}\n");
379 printer->Print("service_ = new ::grpc::RpcService();\n");
380 for (int i = 0; i < service->method_count(); ++i) {
381 const google::protobuf::MethodDescriptor* method = service->method(i);
382 (*vars)["Method"] = method->name();
383 (*vars)["Request"] =
384 grpc_cpp_generator::ClassName(method->input_type(), true);
385 (*vars)["Response"] =
386 grpc_cpp_generator::ClassName(method->output_type(), true);
387 if (NoStreaming(method)) {
388 printer->Print(
389 *vars,
390 "service_->AddMethod(new ::grpc::RpcServiceMethod(\n"
391 " \"/$Service$/$Method$\", ::grpc::RpcMethod::NORMAL_RPC,\n"
392 " new ::grpc::RpcMethodHandler<$Service$::Service, $Request$, "
393 "$Response$>(\n"
394 " std::function<::grpc::Status($Service$::Service*, "
395 "const $Request$*, $Response$*)>("
396 "&$Service$::Service::$Method$), this),\n"
397 " new $Request$, new $Response$));\n");
398 } else if (ClientOnlyStreaming(method)) {
399 printer->Print(
400 *vars,
401 "service_->AddMethod(new ::grpc::RpcServiceMethod(\n"
402 " \"/$Service$/$Method$\", ::grpc::RpcMethod::CLIENT_STREAMING,\n"
403 " new ::grpc::ClientStreamingHandler<"
404 "$Service$::Service, $Request$, $Response$>(\n"
405 " std::function<::grpc::Status($Service$::Service*, "
406 "::grpc::ServerReader<$Request$>*, $Response$*)>("
407 "&$Service$::Service::$Method$), this),\n"
408 " new $Request$, new $Response$));\n");
409 } else if (ServerOnlyStreaming(method)) {
410 printer->Print(
411 *vars,
412 "service_->AddMethod(new ::grpc::RpcServiceMethod(\n"
413 " \"/$Service$/$Method$\", ::grpc::RpcMethod::SERVER_STREAMING,\n"
414 " new ::grpc::ServerStreamingHandler<"
415 "$Service$::Service, $Request$, $Response$>(\n"
416 " std::function<::grpc::Status($Service$::Service*, "
417 "const $Request$*, ::grpc::ServerWriter<$Response$>*)>("
418 "&$Service$::Service::$Method$), this),\n"
419 " new $Request$, new $Response$));\n");
420 } else if (BidiStreaming(method)) {
421 printer->Print(
422 *vars,
423 "service_->AddMethod(new ::grpc::RpcServiceMethod(\n"
424 " \"/$Service$/$Method$\", ::grpc::RpcMethod::BIDI_STREAMING,\n"
425 " new ::grpc::BidiStreamingHandler<"
426 "$Service$::Service, $Request$, $Response$>(\n"
427 " std::function<::grpc::Status($Service$::Service*, "
428 "::grpc::ServerReaderWriter<$Response$, $Request$>*)>("
429 "&$Service$::Service::$Method$), this),\n"
430 " new $Request$, new $Response$));\n");
431 }
432 }
433 printer->Print("return service_;\n");
434 printer->Outdent();
435 printer->Print("}\n\n");
436}
437
438string GetSourceServices(const google::protobuf::FileDescriptor* file) {
439 string output;
440 google::protobuf::io::StringOutputStream output_stream(&output);
441 google::protobuf::io::Printer printer(&output_stream, '$');
442 map<string, string> vars;
443
444 for (int i = 0; i < file->service_count(); ++i) {
445 PrintSourceService(&printer, file->service(0), &vars);
446 printer.Print("\n");
447 }
448 return output;
449}
450
451} // namespace grpc_cpp_generator