blob: 891032343b53ca64b22d2617aa12161a45ecff9a [file] [log] [blame]
nnobleebebb7e2014-12-10 16:31:01 -08001/*
2 *
Craig Tiller06059952015-02-18 08:34:56 -08003 * Copyright 2015, Google Inc.
nnobleebebb7e2014-12-10 16:31:01 -08004 * 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
Nicolas "Pixel" Noble36f53232015-01-16 06:39:58 +010034#include <string>
35#include <map>
36
nnobleebebb7e2014-12-10 16:31:01 -080037#include "src/compiler/cpp_generator.h"
38
39#include "src/compiler/cpp_generator_helpers.h"
40#include <google/protobuf/descriptor.h>
41#include <google/protobuf/descriptor.pb.h>
42#include <google/protobuf/io/printer.h>
43#include <google/protobuf/io/zero_copy_stream_impl_lite.h>
Craig Tiller8c8d0aa2015-02-12 11:38:36 -080044#include <sstream>
nnobleebebb7e2014-12-10 16:31:01 -080045
46namespace grpc_cpp_generator {
47namespace {
48
Craig Tiller8c8d0aa2015-02-12 11:38:36 -080049template <class T>
50std::string as_string(T x) {
51 std::ostringstream out;
52 out << x;
53 return out.str();
54}
55
Craig Tillerecd49342015-01-18 14:36:47 -080056bool NoStreaming(const google::protobuf::MethodDescriptor *method) {
Craig Tillerb5dcec52015-01-13 11:13:42 -080057 return !method->client_streaming() && !method->server_streaming();
nnobleebebb7e2014-12-10 16:31:01 -080058}
59
Craig Tillerecd49342015-01-18 14:36:47 -080060bool ClientOnlyStreaming(const google::protobuf::MethodDescriptor *method) {
Craig Tillerb5dcec52015-01-13 11:13:42 -080061 return method->client_streaming() && !method->server_streaming();
nnobleebebb7e2014-12-10 16:31:01 -080062}
63
Craig Tillerecd49342015-01-18 14:36:47 -080064bool ServerOnlyStreaming(const google::protobuf::MethodDescriptor *method) {
yangg1b151092015-01-09 15:31:05 -080065 return !method->client_streaming() && method->server_streaming();
nnobleebebb7e2014-12-10 16:31:01 -080066}
67
Craig Tillerecd49342015-01-18 14:36:47 -080068bool BidiStreaming(const google::protobuf::MethodDescriptor *method) {
Craig Tillerb5dcec52015-01-13 11:13:42 -080069 return method->client_streaming() && method->server_streaming();
nnobleebebb7e2014-12-10 16:31:01 -080070}
71
Craig Tiller2dff17d2015-02-09 12:42:23 -080072bool HasUnaryCalls(const google::protobuf::FileDescriptor *file) {
73 for (int i = 0; i < file->service_count(); i++) {
74 for (int j = 0; j < file->service(i)->method_count(); j++) {
75 if (NoStreaming(file->service(i)->method(j))) {
76 return true;
77 }
78 }
79 }
80 return false;
81}
82
Craig Tillerecd49342015-01-18 14:36:47 -080083bool HasClientOnlyStreaming(const google::protobuf::FileDescriptor *file) {
nnobleebebb7e2014-12-10 16:31:01 -080084 for (int i = 0; i < file->service_count(); i++) {
85 for (int j = 0; j < file->service(i)->method_count(); j++) {
86 if (ClientOnlyStreaming(file->service(i)->method(j))) {
87 return true;
88 }
89 }
90 }
91 return false;
92}
93
Craig Tillerecd49342015-01-18 14:36:47 -080094bool HasServerOnlyStreaming(const google::protobuf::FileDescriptor *file) {
nnobleebebb7e2014-12-10 16:31:01 -080095 for (int i = 0; i < file->service_count(); i++) {
96 for (int j = 0; j < file->service(i)->method_count(); j++) {
97 if (ServerOnlyStreaming(file->service(i)->method(j))) {
98 return true;
99 }
100 }
101 }
102 return false;
103}
104
Craig Tillerecd49342015-01-18 14:36:47 -0800105bool HasBidiStreaming(const google::protobuf::FileDescriptor *file) {
nnobleebebb7e2014-12-10 16:31:01 -0800106 for (int i = 0; i < file->service_count(); i++) {
107 for (int j = 0; j < file->service(i)->method_count(); j++) {
108 if (BidiStreaming(file->service(i)->method(j))) {
109 return true;
110 }
111 }
112 }
113 return false;
114}
115} // namespace
116
Craig Tillerecd49342015-01-18 14:36:47 -0800117std::string GetHeaderIncludes(const google::protobuf::FileDescriptor *file) {
Nicolas Noblef5c5d802015-01-15 16:36:13 -0800118 std::string temp =
Craig Tiller14a65f92015-02-09 13:13:14 -0800119 "#include <grpc++/impl/internal_stub.h>\n"
120 "#include <grpc++/impl/service_type.h>\n"
121 "#include <grpc++/status.h>\n"
nnobleebebb7e2014-12-10 16:31:01 -0800122 "\n"
123 "namespace grpc {\n"
Craig Tiller8c8d0aa2015-02-12 11:38:36 -0800124 "class CompletionQueue;\n"
nnobleebebb7e2014-12-10 16:31:01 -0800125 "class ChannelInterface;\n"
yangga4b6f5d2014-12-17 15:53:12 -0800126 "class RpcService;\n"
127 "class ServerContext;\n";
Craig Tiller2dff17d2015-02-09 12:42:23 -0800128 if (HasUnaryCalls(file)) {
Craig Tiller5ef5db12015-02-09 12:47:21 -0800129 temp.append(
Yang Gao3a5e5492015-02-18 14:32:38 -0800130 "template <class OutMessage> class ClientAsyncResponseReader;\n");
131 temp.append(
Craig Tiller5ef5db12015-02-09 12:47:21 -0800132 "template <class OutMessage> class ServerAsyncResponseWriter;\n");
Craig Tiller2dff17d2015-02-09 12:42:23 -0800133 }
nnobleebebb7e2014-12-10 16:31:01 -0800134 if (HasClientOnlyStreaming(file)) {
135 temp.append("template <class OutMessage> class ClientWriter;\n");
136 temp.append("template <class InMessage> class ServerReader;\n");
Craig Tiller2dff17d2015-02-09 12:42:23 -0800137 temp.append("template <class OutMessage> class ClientAsyncWriter;\n");
Yang Gao005f18a2015-02-13 10:22:33 -0800138 temp.append("template <class OutMessage, class InMessage> class ServerAsyncReader;\n");
nnobleebebb7e2014-12-10 16:31:01 -0800139 }
140 if (HasServerOnlyStreaming(file)) {
141 temp.append("template <class InMessage> class ClientReader;\n");
142 temp.append("template <class OutMessage> class ServerWriter;\n");
Craig Tiller2dff17d2015-02-09 12:42:23 -0800143 temp.append("template <class OutMessage> class ClientAsyncReader;\n");
144 temp.append("template <class InMessage> class ServerAsyncWriter;\n");
nnobleebebb7e2014-12-10 16:31:01 -0800145 }
146 if (HasBidiStreaming(file)) {
147 temp.append(
148 "template <class OutMessage, class InMessage>\n"
149 "class ClientReaderWriter;\n");
150 temp.append(
151 "template <class OutMessage, class InMessage>\n"
152 "class ServerReaderWriter;\n");
Craig Tiller225f7be2015-02-09 22:32:37 -0800153 temp.append(
154 "template <class OutMessage, class InMessage>\n"
155 "class ClientAsyncReaderWriter;\n");
156 temp.append(
157 "template <class OutMessage, class InMessage>\n"
158 "class ServerAsyncReaderWriter;\n");
nnobleebebb7e2014-12-10 16:31:01 -0800159 }
160 temp.append("} // namespace grpc\n");
161 return temp;
162}
163
Nicolas Noblef5c5d802015-01-15 16:36:13 -0800164std::string GetSourceIncludes() {
Yang Gao3a5e5492015-02-18 14:32:38 -0800165 return "#include <grpc++/async_unary_call.h>\n"
166 "#include <grpc++/channel_interface.h>\n"
Craig Tiller80e00a82015-02-09 20:54:25 -0800167 "#include <grpc++/impl/client_unary_call.h>\n"
Craig Tiller2dff17d2015-02-09 12:42:23 -0800168 "#include <grpc++/impl/rpc_method.h>\n"
169 "#include <grpc++/impl/rpc_service_method.h>\n"
Craig Tiller14a65f92015-02-09 13:13:14 -0800170 "#include <grpc++/impl/service_type.h>\n"
Craig Tiller2dff17d2015-02-09 12:42:23 -0800171 "#include <grpc++/stream.h>\n";
nnobleebebb7e2014-12-10 16:31:01 -0800172}
173
Craig Tillerecd49342015-01-18 14:36:47 -0800174void PrintHeaderClientMethod(google::protobuf::io::Printer *printer,
175 const google::protobuf::MethodDescriptor *method,
176 std::map<std::string, std::string> *vars) {
nnobleebebb7e2014-12-10 16:31:01 -0800177 (*vars)["Method"] = method->name();
178 (*vars)["Request"] =
179 grpc_cpp_generator::ClassName(method->input_type(), true);
180 (*vars)["Response"] =
181 grpc_cpp_generator::ClassName(method->output_type(), true);
182 if (NoStreaming(method)) {
183 printer->Print(*vars,
184 "::grpc::Status $Method$(::grpc::ClientContext* context, "
Craig Tiller5ef5db12015-02-09 12:47:21 -0800185 "const $Request$& request, $Response$* response);\n");
Craig Tillerfd1b49b2015-02-23 12:53:39 -0800186 printer->Print(
187 *vars,
188 "std::unique_ptr< ::grpc::ClientAsyncResponseReader< $Response$>> "
189 "$Method$(::grpc::ClientContext* context, "
190 "const $Request$& request, "
191 "::grpc::CompletionQueue* cq, void* tag);\n");
nnobleebebb7e2014-12-10 16:31:01 -0800192 } else if (ClientOnlyStreaming(method)) {
Craig Tillerfd1b49b2015-02-23 12:53:39 -0800193 printer->Print(
194 *vars,
195 "std::unique_ptr< ::grpc::ClientWriter< $Request$>> $Method$("
196 "::grpc::ClientContext* context, $Response$* response);\n");
197 printer->Print(
198 *vars,
199 "std::unique_ptr< ::grpc::ClientAsyncWriter< $Request$>> $Method$("
200 "::grpc::ClientContext* context, $Response$* response, "
201 "::grpc::CompletionQueue* cq, void* tag);\n");
nnobleebebb7e2014-12-10 16:31:01 -0800202 } else if (ServerOnlyStreaming(method)) {
203 printer->Print(
204 *vars,
Craig Tillerfd1b49b2015-02-23 12:53:39 -0800205 "std::unique_ptr< ::grpc::ClientReader< $Response$>> $Method$("
Yang Gao07d83042015-02-13 14:11:31 -0800206 "::grpc::ClientContext* context, const $Request$& request);\n");
Craig Tillerfd1b49b2015-02-23 12:53:39 -0800207 printer->Print(
208 *vars,
209 "std::unique_ptr< ::grpc::ClientAsyncReader< $Response$>> $Method$("
210 "::grpc::ClientContext* context, const $Request$& request, "
211 "::grpc::CompletionQueue* cq, void* tag);\n");
nnobleebebb7e2014-12-10 16:31:01 -0800212 } else if (BidiStreaming(method)) {
Craig Tillerfd1b49b2015-02-23 12:53:39 -0800213 printer->Print(
214 *vars,
215 "std::unique_ptr< ::grpc::ClientReaderWriter< $Request$, $Response$>> "
216 "$Method$(::grpc::ClientContext* context);\n");
nnobleebebb7e2014-12-10 16:31:01 -0800217 printer->Print(*vars,
Craig Tillerfd1b49b2015-02-23 12:53:39 -0800218 "std::unique_ptr< ::grpc::ClientAsyncReaderWriter< "
219 "$Request$, $Response$>> "
Craig Tiller5ef5db12015-02-09 12:47:21 -0800220 "$Method$(::grpc::ClientContext* context, "
Yang Gao068c85b2015-02-12 15:21:24 -0800221 "::grpc::CompletionQueue* cq, void* tag);\n");
nnobleebebb7e2014-12-10 16:31:01 -0800222 }
223}
224
Craig Tiller5ef5db12015-02-09 12:47:21 -0800225void PrintHeaderServerMethodSync(
226 google::protobuf::io::Printer *printer,
227 const google::protobuf::MethodDescriptor *method,
228 std::map<std::string, std::string> *vars) {
nnobleebebb7e2014-12-10 16:31:01 -0800229 (*vars)["Method"] = method->name();
230 (*vars)["Request"] =
231 grpc_cpp_generator::ClassName(method->input_type(), true);
232 (*vars)["Response"] =
233 grpc_cpp_generator::ClassName(method->output_type(), true);
234 if (NoStreaming(method)) {
235 printer->Print(*vars,
yangga4b6f5d2014-12-17 15:53:12 -0800236 "virtual ::grpc::Status $Method$("
237 "::grpc::ServerContext* context, const $Request$* request, "
nnobleebebb7e2014-12-10 16:31:01 -0800238 "$Response$* response);\n");
239 } else if (ClientOnlyStreaming(method)) {
240 printer->Print(*vars,
241 "virtual ::grpc::Status $Method$("
yangga4b6f5d2014-12-17 15:53:12 -0800242 "::grpc::ServerContext* context, "
Yang Gao1ff11f62015-01-14 11:45:32 -0800243 "::grpc::ServerReader< $Request$>* reader, "
nnobleebebb7e2014-12-10 16:31:01 -0800244 "$Response$* response);\n");
245 } else if (ServerOnlyStreaming(method)) {
246 printer->Print(*vars,
yangga4b6f5d2014-12-17 15:53:12 -0800247 "virtual ::grpc::Status $Method$("
248 "::grpc::ServerContext* context, const $Request$* request, "
Yang Gao1ff11f62015-01-14 11:45:32 -0800249 "::grpc::ServerWriter< $Response$>* writer);\n");
nnobleebebb7e2014-12-10 16:31:01 -0800250 } else if (BidiStreaming(method)) {
Yang Gao5680ff42015-01-14 12:14:21 -0800251 printer->Print(
252 *vars,
253 "virtual ::grpc::Status $Method$("
254 "::grpc::ServerContext* context, "
255 "::grpc::ServerReaderWriter< $Response$, $Request$>* stream);"
256 "\n");
nnobleebebb7e2014-12-10 16:31:01 -0800257 }
258}
259
Craig Tiller5ef5db12015-02-09 12:47:21 -0800260void PrintHeaderServerMethodAsync(
261 google::protobuf::io::Printer *printer,
262 const google::protobuf::MethodDescriptor *method,
263 std::map<std::string, std::string> *vars) {
Craig Tiller2dff17d2015-02-09 12:42:23 -0800264 (*vars)["Method"] = method->name();
265 (*vars)["Request"] =
266 grpc_cpp_generator::ClassName(method->input_type(), true);
267 (*vars)["Response"] =
268 grpc_cpp_generator::ClassName(method->output_type(), true);
269 if (NoStreaming(method)) {
270 printer->Print(*vars,
Yang Gaoca3cb3e2015-02-12 00:05:11 -0800271 "void Request$Method$("
Craig Tiller2dff17d2015-02-09 12:42:23 -0800272 "::grpc::ServerContext* context, $Request$* request, "
273 "::grpc::ServerAsyncResponseWriter< $Response$>* response, "
274 "::grpc::CompletionQueue* cq, void *tag);\n");
275 } else if (ClientOnlyStreaming(method)) {
276 printer->Print(*vars,
Yang Gaoca3cb3e2015-02-12 00:05:11 -0800277 "void Request$Method$("
Craig Tiller2dff17d2015-02-09 12:42:23 -0800278 "::grpc::ServerContext* context, "
Yang Gao005f18a2015-02-13 10:22:33 -0800279 "::grpc::ServerAsyncReader< $Response$, $Request$>* reader, "
Craig Tiller2dff17d2015-02-09 12:42:23 -0800280 "::grpc::CompletionQueue* cq, void *tag);\n");
281 } else if (ServerOnlyStreaming(method)) {
282 printer->Print(*vars,
Yang Gaoca3cb3e2015-02-12 00:05:11 -0800283 "void Request$Method$("
Craig Tiller2dff17d2015-02-09 12:42:23 -0800284 "::grpc::ServerContext* context, $Request$* request, "
285 "::grpc::ServerAsyncWriter< $Response$>* writer, "
286 "::grpc::CompletionQueue* cq, void *tag);\n");
287 } else if (BidiStreaming(method)) {
288 printer->Print(
289 *vars,
Yang Gaoca3cb3e2015-02-12 00:05:11 -0800290 "void Request$Method$("
Craig Tiller2dff17d2015-02-09 12:42:23 -0800291 "::grpc::ServerContext* context, "
Craig Tiller225f7be2015-02-09 22:32:37 -0800292 "::grpc::ServerAsyncReaderWriter< $Response$, $Request$>* stream, "
Craig Tiller5ef5db12015-02-09 12:47:21 -0800293 "::grpc::CompletionQueue* cq, void *tag);\n");
Craig Tiller2dff17d2015-02-09 12:42:23 -0800294 }
295}
296
Craig Tillerecd49342015-01-18 14:36:47 -0800297void PrintHeaderService(google::protobuf::io::Printer *printer,
298 const google::protobuf::ServiceDescriptor *service,
299 std::map<std::string, std::string> *vars) {
nnobleebebb7e2014-12-10 16:31:01 -0800300 (*vars)["Service"] = service->name();
301
302 printer->Print(*vars,
Craig Tiller2dff17d2015-02-09 12:42:23 -0800303 "class $Service$ final {\n"
nnobleebebb7e2014-12-10 16:31:01 -0800304 " public:\n");
305 printer->Indent();
306
307 // Client side
Craig Tillerb5dcec52015-01-13 11:13:42 -0800308 printer->Print(
Craig Tiller2dff17d2015-02-09 12:42:23 -0800309 "class Stub final : public ::grpc::InternalStub {\n"
Craig Tillerb5dcec52015-01-13 11:13:42 -0800310 " public:\n");
nnobleebebb7e2014-12-10 16:31:01 -0800311 printer->Indent();
312 for (int i = 0; i < service->method_count(); ++i) {
313 PrintHeaderClientMethod(printer, service->method(i), vars);
314 }
315 printer->Outdent();
316 printer->Print("};\n");
317 printer->Print(
Craig Tillerfd1b49b2015-02-23 12:53:39 -0800318 "static std::unique_ptr<Stub> NewStub(const std::shared_ptr< "
319 "::grpc::ChannelInterface>& "
nnobleebebb7e2014-12-10 16:31:01 -0800320 "channel);\n");
321
322 printer->Print("\n");
323
Craig Tiller2dff17d2015-02-09 12:42:23 -0800324 // Server side - Synchronous
Craig Tillerb5dcec52015-01-13 11:13:42 -0800325 printer->Print(
Craig Tiller14a65f92015-02-09 13:13:14 -0800326 "class Service : public ::grpc::SynchronousService {\n"
Craig Tillerb5dcec52015-01-13 11:13:42 -0800327 " public:\n");
nnobleebebb7e2014-12-10 16:31:01 -0800328 printer->Indent();
329 printer->Print("Service() : service_(nullptr) {}\n");
330 printer->Print("virtual ~Service();\n");
331 for (int i = 0; i < service->method_count(); ++i) {
Craig Tiller2dff17d2015-02-09 12:42:23 -0800332 PrintHeaderServerMethodSync(printer, service->method(i), vars);
333 }
Craig Tiller40fcdaf2015-02-09 15:43:34 -0800334 printer->Print("::grpc::RpcService* service() override final;\n");
Craig Tiller2dff17d2015-02-09 12:42:23 -0800335 printer->Outdent();
336 printer->Print(
337 " private:\n"
338 " ::grpc::RpcService* service_;\n");
339 printer->Print("};\n");
340
341 // Server side - Asynchronous
342 printer->Print(
Craig Tiller14a65f92015-02-09 13:13:14 -0800343 "class AsyncService final : public ::grpc::AsynchronousService {\n"
Craig Tiller2dff17d2015-02-09 12:42:23 -0800344 " public:\n");
345 printer->Indent();
Craig Tiller8c8d0aa2015-02-12 11:38:36 -0800346 (*vars)["MethodCount"] = as_string(service->method_count());
347 printer->Print("explicit AsyncService(::grpc::CompletionQueue* cq);\n");
Craig Tiller0220cf12015-02-12 17:39:26 -0800348 printer->Print("~AsyncService() {};\n");
Craig Tiller2dff17d2015-02-09 12:42:23 -0800349 for (int i = 0; i < service->method_count(); ++i) {
350 PrintHeaderServerMethodAsync(printer, service->method(i), vars);
nnobleebebb7e2014-12-10 16:31:01 -0800351 }
nnobleebebb7e2014-12-10 16:31:01 -0800352 printer->Outdent();
nnobleebebb7e2014-12-10 16:31:01 -0800353 printer->Print("};\n");
354
355 printer->Outdent();
356 printer->Print("};\n");
357}
358
Craig Tillerecd49342015-01-18 14:36:47 -0800359std::string GetHeaderServices(const google::protobuf::FileDescriptor *file) {
Nicolas Noblef5c5d802015-01-15 16:36:13 -0800360 std::string output;
nnobleebebb7e2014-12-10 16:31:01 -0800361 google::protobuf::io::StringOutputStream output_stream(&output);
362 google::protobuf::io::Printer printer(&output_stream, '$');
Nicolas Noblef5c5d802015-01-15 16:36:13 -0800363 std::map<std::string, std::string> vars;
nnobleebebb7e2014-12-10 16:31:01 -0800364
365 for (int i = 0; i < file->service_count(); ++i) {
samuelwca9f3592014-12-15 14:22:04 -0800366 PrintHeaderService(&printer, file->service(i), &vars);
nnobleebebb7e2014-12-10 16:31:01 -0800367 printer.Print("\n");
368 }
369 return output;
370}
371
Craig Tillerecd49342015-01-18 14:36:47 -0800372void PrintSourceClientMethod(google::protobuf::io::Printer *printer,
373 const google::protobuf::MethodDescriptor *method,
374 std::map<std::string, std::string> *vars) {
nnobleebebb7e2014-12-10 16:31:01 -0800375 (*vars)["Method"] = method->name();
376 (*vars)["Request"] =
377 grpc_cpp_generator::ClassName(method->input_type(), true);
378 (*vars)["Response"] =
379 grpc_cpp_generator::ClassName(method->output_type(), true);
380 if (NoStreaming(method)) {
381 printer->Print(*vars,
382 "::grpc::Status $Service$::Stub::$Method$("
383 "::grpc::ClientContext* context, "
384 "const $Request$& request, $Response$* response) {\n");
385 printer->Print(*vars,
Craig Tiller1c9a2a92015-02-12 14:10:25 -0800386 " return ::grpc::BlockingUnaryCall(channel(),"
Craig Tiller8c8d0aa2015-02-12 11:38:36 -0800387 "::grpc::RpcMethod($Service$_method_names[$Idx$]), "
nnobleebebb7e2014-12-10 16:31:01 -0800388 "context, request, response);\n"
389 "}\n\n");
Yang Gao5680ff42015-01-14 12:14:21 -0800390 printer->Print(
391 *vars,
Craig Tillerfd1b49b2015-02-23 12:53:39 -0800392 "std::unique_ptr< ::grpc::ClientAsyncResponseReader< $Response$>> "
393 "$Service$::Stub::$Method$(::grpc::ClientContext* context, "
394 "const $Request$& request, "
395 "::grpc::CompletionQueue* cq, void* tag) {\n");
yangg5bcea0d2015-01-06 10:35:03 -0800396 printer->Print(*vars,
Craig Tillerfd1b49b2015-02-23 12:53:39 -0800397 " return std::unique_ptr< "
398 "::grpc::ClientAsyncResponseReader< $Response$>>(new "
399 "::grpc::ClientAsyncResponseReader< $Response$>("
400 "channel(), cq, "
401 "::grpc::RpcMethod($Service$_method_names[$Idx$]), "
402 "context, request, tag));\n"
403 "}\n\n");
404 } else if (ClientOnlyStreaming(method)) {
405 printer->Print(*vars,
406 "std::unique_ptr< ::grpc::ClientWriter< $Request$>> "
407 "$Service$::Stub::$Method$("
408 "::grpc::ClientContext* context, $Response$* response) {\n");
409 printer->Print(*vars,
410 " return std::unique_ptr< ::grpc::ClientWriter< "
411 "$Request$>>(new ::grpc::ClientWriter< $Request$>("
Craig Tillerc4965752015-02-09 09:51:00 -0800412 "channel(),"
Craig Tiller8c8d0aa2015-02-12 11:38:36 -0800413 "::grpc::RpcMethod($Service$_method_names[$Idx$], "
yangg5bcea0d2015-01-06 10:35:03 -0800414 "::grpc::RpcMethod::RpcType::CLIENT_STREAMING), "
Craig Tillerfd1b49b2015-02-23 12:53:39 -0800415 "context, response));\n"
yangg5bcea0d2015-01-06 10:35:03 -0800416 "}\n\n");
Yang Gao068c85b2015-02-12 15:21:24 -0800417 printer->Print(*vars,
Craig Tillerfd1b49b2015-02-23 12:53:39 -0800418 "std::unique_ptr< ::grpc::ClientAsyncWriter< $Request$>> "
419 "$Service$::Stub::$Method$("
420 "::grpc::ClientContext* context, $Response$* response, "
421 "::grpc::CompletionQueue* cq, void* tag) {\n");
422 printer->Print(*vars,
423 " return std::unique_ptr< ::grpc::ClientAsyncWriter< "
424 "$Request$>>(new ::grpc::ClientAsyncWriter< $Request$>("
Yang Gao068c85b2015-02-12 15:21:24 -0800425 "channel(), cq, "
426 "::grpc::RpcMethod($Service$_method_names[$Idx$], "
427 "::grpc::RpcMethod::RpcType::CLIENT_STREAMING), "
Craig Tillerfd1b49b2015-02-23 12:53:39 -0800428 "context, response, tag));\n"
Yang Gao068c85b2015-02-12 15:21:24 -0800429 "}\n\n");
nnobleebebb7e2014-12-10 16:31:01 -0800430 } else if (ServerOnlyStreaming(method)) {
431 printer->Print(
432 *vars,
Craig Tillerfd1b49b2015-02-23 12:53:39 -0800433 "std::unique_ptr< ::grpc::ClientReader< $Response$>> "
434 "$Service$::Stub::$Method$("
Yang Gao07d83042015-02-13 14:11:31 -0800435 "::grpc::ClientContext* context, const $Request$& request) {\n");
yangg5bcea0d2015-01-06 10:35:03 -0800436 printer->Print(*vars,
Craig Tillerfd1b49b2015-02-23 12:53:39 -0800437 " return std::unique_ptr< ::grpc::ClientReader< "
438 "$Response$>>(new ::grpc::ClientReader< $Response$>("
Craig Tillerc4965752015-02-09 09:51:00 -0800439 "channel(),"
Craig Tiller8c8d0aa2015-02-12 11:38:36 -0800440 "::grpc::RpcMethod($Service$_method_names[$Idx$], "
yangg5bcea0d2015-01-06 10:35:03 -0800441 "::grpc::RpcMethod::RpcType::SERVER_STREAMING), "
Craig Tillerfd1b49b2015-02-23 12:53:39 -0800442 "context, request));\n"
yangg5bcea0d2015-01-06 10:35:03 -0800443 "}\n\n");
Yang Gao068c85b2015-02-12 15:21:24 -0800444 printer->Print(*vars,
Craig Tillerfd1b49b2015-02-23 12:53:39 -0800445 "std::unique_ptr< ::grpc::ClientAsyncReader< $Response$>> "
446 "$Service$::Stub::$Method$("
447 "::grpc::ClientContext* context, const $Request$& request, "
448 "::grpc::CompletionQueue* cq, void* tag) {\n");
449 printer->Print(*vars,
450 " return std::unique_ptr< ::grpc::ClientAsyncReader< "
451 "$Response$>>(new ::grpc::ClientAsyncReader< $Response$>("
Yang Gao068c85b2015-02-12 15:21:24 -0800452 "channel(), cq, "
453 "::grpc::RpcMethod($Service$_method_names[$Idx$], "
454 "::grpc::RpcMethod::RpcType::SERVER_STREAMING), "
Craig Tillerfd1b49b2015-02-23 12:53:39 -0800455 "context, request, tag));\n"
Yang Gao068c85b2015-02-12 15:21:24 -0800456 "}\n\n");
nnobleebebb7e2014-12-10 16:31:01 -0800457 } else if (BidiStreaming(method)) {
458 printer->Print(
459 *vars,
Craig Tillerfd1b49b2015-02-23 12:53:39 -0800460 "std::unique_ptr< ::grpc::ClientReaderWriter< $Request$, $Response$>> "
nnobleebebb7e2014-12-10 16:31:01 -0800461 "$Service$::Stub::$Method$(::grpc::ClientContext* context) {\n");
Craig Tillerfd1b49b2015-02-23 12:53:39 -0800462 printer->Print(*vars,
463 " return std::unique_ptr< ::grpc::ClientReaderWriter< "
464 "$Request$, $Response$>>(new ::grpc::ClientReaderWriter< "
465 "$Request$, $Response$>("
466 "channel(),"
467 "::grpc::RpcMethod($Service$_method_names[$Idx$], "
468 "::grpc::RpcMethod::RpcType::BIDI_STREAMING), "
469 "context));\n"
470 "}\n\n");
471 printer->Print(*vars,
472 "std::unique_ptr< ::grpc::ClientAsyncReaderWriter< "
473 "$Request$, $Response$>> "
474 "$Service$::Stub::$Method$(::grpc::ClientContext* context, "
475 "::grpc::CompletionQueue* cq, void* tag) {\n");
476 printer->Print(*vars,
477 " return std::unique_ptr< ::grpc::ClientAsyncReaderWriter< "
478 "$Request$, $Response$>>(new "
479 "::grpc::ClientAsyncReaderWriter< $Request$, $Response$>("
480 "channel(), cq, "
481 "::grpc::RpcMethod($Service$_method_names[$Idx$], "
482 "::grpc::RpcMethod::RpcType::BIDI_STREAMING), "
483 "context, tag));\n"
484 "}\n\n");
nnobleebebb7e2014-12-10 16:31:01 -0800485 }
486}
487
Craig Tillerecd49342015-01-18 14:36:47 -0800488void PrintSourceServerMethod(google::protobuf::io::Printer *printer,
489 const google::protobuf::MethodDescriptor *method,
490 std::map<std::string, std::string> *vars) {
nnobleebebb7e2014-12-10 16:31:01 -0800491 (*vars)["Method"] = method->name();
492 (*vars)["Request"] =
493 grpc_cpp_generator::ClassName(method->input_type(), true);
494 (*vars)["Response"] =
495 grpc_cpp_generator::ClassName(method->output_type(), true);
496 if (NoStreaming(method)) {
497 printer->Print(*vars,
498 "::grpc::Status $Service$::Service::$Method$("
yangga4b6f5d2014-12-17 15:53:12 -0800499 "::grpc::ServerContext* context, "
nnobleebebb7e2014-12-10 16:31:01 -0800500 "const $Request$* request, $Response$* response) {\n");
501 printer->Print(
502 " return ::grpc::Status("
503 "::grpc::StatusCode::UNIMPLEMENTED);\n");
504 printer->Print("}\n\n");
505 } else if (ClientOnlyStreaming(method)) {
506 printer->Print(*vars,
507 "::grpc::Status $Service$::Service::$Method$("
yangga4b6f5d2014-12-17 15:53:12 -0800508 "::grpc::ServerContext* context, "
Yang Gao1ff11f62015-01-14 11:45:32 -0800509 "::grpc::ServerReader< $Request$>* reader, "
nnobleebebb7e2014-12-10 16:31:01 -0800510 "$Response$* response) {\n");
511 printer->Print(
512 " return ::grpc::Status("
513 "::grpc::StatusCode::UNIMPLEMENTED);\n");
514 printer->Print("}\n\n");
515 } else if (ServerOnlyStreaming(method)) {
516 printer->Print(*vars,
517 "::grpc::Status $Service$::Service::$Method$("
yangga4b6f5d2014-12-17 15:53:12 -0800518 "::grpc::ServerContext* context, "
nnobleebebb7e2014-12-10 16:31:01 -0800519 "const $Request$* request, "
Yang Gao1ff11f62015-01-14 11:45:32 -0800520 "::grpc::ServerWriter< $Response$>* writer) {\n");
nnobleebebb7e2014-12-10 16:31:01 -0800521 printer->Print(
522 " return ::grpc::Status("
523 "::grpc::StatusCode::UNIMPLEMENTED);\n");
524 printer->Print("}\n\n");
525 } else if (BidiStreaming(method)) {
526 printer->Print(*vars,
527 "::grpc::Status $Service$::Service::$Method$("
yangga4b6f5d2014-12-17 15:53:12 -0800528 "::grpc::ServerContext* context, "
Yang Gao1ff11f62015-01-14 11:45:32 -0800529 "::grpc::ServerReaderWriter< $Response$, $Request$>* "
nnobleebebb7e2014-12-10 16:31:01 -0800530 "stream) {\n");
531 printer->Print(
532 " return ::grpc::Status("
533 "::grpc::StatusCode::UNIMPLEMENTED);\n");
534 printer->Print("}\n\n");
535 }
536}
537
Craig Tiller8c8d0aa2015-02-12 11:38:36 -0800538void PrintSourceServerAsyncMethod(
539 google::protobuf::io::Printer *printer,
540 const google::protobuf::MethodDescriptor *method,
541 std::map<std::string, std::string> *vars) {
Craig Tiller225f7be2015-02-09 22:32:37 -0800542 (*vars)["Method"] = method->name();
543 (*vars)["Request"] =
544 grpc_cpp_generator::ClassName(method->input_type(), true);
545 (*vars)["Response"] =
546 grpc_cpp_generator::ClassName(method->output_type(), true);
547 if (NoStreaming(method)) {
548 printer->Print(*vars,
Yang Gaoca3cb3e2015-02-12 00:05:11 -0800549 "void $Service$::AsyncService::Request$Method$("
Craig Tiller225f7be2015-02-09 22:32:37 -0800550 "::grpc::ServerContext* context, "
551 "$Request$* request, "
552 "::grpc::ServerAsyncResponseWriter< $Response$>* response, "
553 "::grpc::CompletionQueue* cq, void* tag) {\n");
Craig Tiller1c9a2a92015-02-12 14:10:25 -0800554 printer->Print(
555 *vars,
556 " AsynchronousService::RequestAsyncUnary($Idx$, context, request, response, cq, tag);\n");
Craig Tiller225f7be2015-02-09 22:32:37 -0800557 printer->Print("}\n\n");
558 } else if (ClientOnlyStreaming(method)) {
559 printer->Print(*vars,
Yang Gaoca3cb3e2015-02-12 00:05:11 -0800560 "void $Service$::AsyncService::Request$Method$("
Craig Tiller225f7be2015-02-09 22:32:37 -0800561 "::grpc::ServerContext* context, "
Yang Gao005f18a2015-02-13 10:22:33 -0800562 "::grpc::ServerAsyncReader< $Response$, $Request$>* reader, "
Craig Tiller225f7be2015-02-09 22:32:37 -0800563 "::grpc::CompletionQueue* cq, void* tag) {\n");
Craig Tiller1c9a2a92015-02-12 14:10:25 -0800564 printer->Print(
565 *vars,
566 " AsynchronousService::RequestClientStreaming($Idx$, context, reader, cq, tag);\n");
Craig Tiller225f7be2015-02-09 22:32:37 -0800567 printer->Print("}\n\n");
568 } else if (ServerOnlyStreaming(method)) {
569 printer->Print(*vars,
Yang Gaoca3cb3e2015-02-12 00:05:11 -0800570 "void $Service$::AsyncService::Request$Method$("
Craig Tiller225f7be2015-02-09 22:32:37 -0800571 "::grpc::ServerContext* context, "
572 "$Request$* request, "
573 "::grpc::ServerAsyncWriter< $Response$>* writer, "
574 "::grpc::CompletionQueue* cq, void* tag) {\n");
Craig Tiller1c9a2a92015-02-12 14:10:25 -0800575 printer->Print(
576 *vars,
577 " AsynchronousService::RequestServerStreaming($Idx$, context, request, writer, cq, tag);\n");
Craig Tiller225f7be2015-02-09 22:32:37 -0800578 printer->Print("}\n\n");
579 } else if (BidiStreaming(method)) {
Craig Tiller8c8d0aa2015-02-12 11:38:36 -0800580 printer->Print(
581 *vars,
582 "void $Service$::AsyncService::Request$Method$("
583 "::grpc::ServerContext* context, "
584 "::grpc::ServerAsyncReaderWriter< $Response$, $Request$>* stream, "
585 "::grpc::CompletionQueue* cq, void *tag) {\n");
Craig Tiller1c9a2a92015-02-12 14:10:25 -0800586 printer->Print(
587 *vars,
588 " AsynchronousService::RequestBidiStreaming($Idx$, context, stream, cq, tag);\n");
Craig Tiller225f7be2015-02-09 22:32:37 -0800589 printer->Print("}\n\n");
590 }
591}
592
Craig Tillerecd49342015-01-18 14:36:47 -0800593void PrintSourceService(google::protobuf::io::Printer *printer,
594 const google::protobuf::ServiceDescriptor *service,
595 std::map<std::string, std::string> *vars) {
nnobleebebb7e2014-12-10 16:31:01 -0800596 (*vars)["Service"] = service->name();
Craig Tiller8c8d0aa2015-02-12 11:38:36 -0800597
598 printer->Print(*vars, "static const char* $Service$_method_names[] = {\n");
599 for (int i = 0; i < service->method_count(); ++i) {
600 (*vars)["Method"] = service->method(i)->name();
601 printer->Print(*vars, " \"/$Package$$Service$/$Method$\",\n");
602 }
603 printer->Print(*vars, "};\n\n");
604
Yang Gao5680ff42015-01-14 12:14:21 -0800605 printer->Print(
606 *vars,
Craig Tillerfd1b49b2015-02-23 12:53:39 -0800607 "std::unique_ptr< $Service$::Stub> $Service$::NewStub("
Yang Gao5680ff42015-01-14 12:14:21 -0800608 "const std::shared_ptr< ::grpc::ChannelInterface>& channel) {\n"
Craig Tillerfd1b49b2015-02-23 12:53:39 -0800609 " std::unique_ptr< $Service$::Stub> stub(new $Service$::Stub());\n"
Yang Gao5680ff42015-01-14 12:14:21 -0800610 " stub->set_channel(channel);\n"
611 " return stub;\n"
612 "};\n\n");
nnobleebebb7e2014-12-10 16:31:01 -0800613 for (int i = 0; i < service->method_count(); ++i) {
Craig Tiller8c8d0aa2015-02-12 11:38:36 -0800614 (*vars)["Idx"] = as_string(i);
nnobleebebb7e2014-12-10 16:31:01 -0800615 PrintSourceClientMethod(printer, service->method(i), vars);
616 }
617
Craig Tiller8c8d0aa2015-02-12 11:38:36 -0800618 (*vars)["MethodCount"] = as_string(service->method_count());
619 printer->Print(
620 *vars,
621 "$Service$::AsyncService::AsyncService(::grpc::CompletionQueue* cq) : "
622 "::grpc::AsynchronousService(cq, $Service$_method_names, $MethodCount$) "
623 "{}\n\n");
624
nnobleebebb7e2014-12-10 16:31:01 -0800625 printer->Print(*vars,
626 "$Service$::Service::~Service() {\n"
627 " delete service_;\n"
628 "}\n\n");
629 for (int i = 0; i < service->method_count(); ++i) {
Craig Tiller1c9a2a92015-02-12 14:10:25 -0800630 (*vars)["Idx"] = as_string(i);
nnobleebebb7e2014-12-10 16:31:01 -0800631 PrintSourceServerMethod(printer, service->method(i), vars);
Craig Tiller225f7be2015-02-09 22:32:37 -0800632 PrintSourceServerAsyncMethod(printer, service->method(i), vars);
nnobleebebb7e2014-12-10 16:31:01 -0800633 }
634 printer->Print(*vars,
Craig Tillerb5dcec52015-01-13 11:13:42 -0800635 "::grpc::RpcService* $Service$::Service::service() {\n");
nnobleebebb7e2014-12-10 16:31:01 -0800636 printer->Indent();
Craig Tillerb5dcec52015-01-13 11:13:42 -0800637 printer->Print(
638 "if (service_ != nullptr) {\n"
639 " return service_;\n"
640 "}\n");
nnobleebebb7e2014-12-10 16:31:01 -0800641 printer->Print("service_ = new ::grpc::RpcService();\n");
642 for (int i = 0; i < service->method_count(); ++i) {
Craig Tillerecd49342015-01-18 14:36:47 -0800643 const google::protobuf::MethodDescriptor *method = service->method(i);
Craig Tiller8c8d0aa2015-02-12 11:38:36 -0800644 (*vars)["Idx"] = as_string(i);
nnobleebebb7e2014-12-10 16:31:01 -0800645 (*vars)["Method"] = method->name();
646 (*vars)["Request"] =
647 grpc_cpp_generator::ClassName(method->input_type(), true);
648 (*vars)["Response"] =
649 grpc_cpp_generator::ClassName(method->output_type(), true);
650 if (NoStreaming(method)) {
651 printer->Print(
652 *vars,
653 "service_->AddMethod(new ::grpc::RpcServiceMethod(\n"
Craig Tiller8c8d0aa2015-02-12 11:38:36 -0800654 " $Service$_method_names[$Idx$],\n"
yangg5bcea0d2015-01-06 10:35:03 -0800655 " ::grpc::RpcMethod::NORMAL_RPC,\n"
Yang Gao1ff11f62015-01-14 11:45:32 -0800656 " new ::grpc::RpcMethodHandler< $Service$::Service, $Request$, "
nnobleebebb7e2014-12-10 16:31:01 -0800657 "$Response$>(\n"
Yang Gao1ff11f62015-01-14 11:45:32 -0800658 " std::function< ::grpc::Status($Service$::Service*, "
yangga4b6f5d2014-12-17 15:53:12 -0800659 "::grpc::ServerContext*, const $Request$*, $Response$*)>("
nnobleebebb7e2014-12-10 16:31:01 -0800660 "&$Service$::Service::$Method$), this),\n"
661 " new $Request$, new $Response$));\n");
662 } else if (ClientOnlyStreaming(method)) {
663 printer->Print(
664 *vars,
665 "service_->AddMethod(new ::grpc::RpcServiceMethod(\n"
Craig Tiller8c8d0aa2015-02-12 11:38:36 -0800666 " $Service$_method_names[$Idx$],\n"
yangg5bcea0d2015-01-06 10:35:03 -0800667 " ::grpc::RpcMethod::CLIENT_STREAMING,\n"
Yang Gao1ff11f62015-01-14 11:45:32 -0800668 " new ::grpc::ClientStreamingHandler< "
nnobleebebb7e2014-12-10 16:31:01 -0800669 "$Service$::Service, $Request$, $Response$>(\n"
Yang Gao1ff11f62015-01-14 11:45:32 -0800670 " std::function< ::grpc::Status($Service$::Service*, "
yangga4b6f5d2014-12-17 15:53:12 -0800671 "::grpc::ServerContext*, "
Yang Gao1ff11f62015-01-14 11:45:32 -0800672 "::grpc::ServerReader< $Request$>*, $Response$*)>("
nnobleebebb7e2014-12-10 16:31:01 -0800673 "&$Service$::Service::$Method$), this),\n"
674 " new $Request$, new $Response$));\n");
675 } else if (ServerOnlyStreaming(method)) {
676 printer->Print(
677 *vars,
678 "service_->AddMethod(new ::grpc::RpcServiceMethod(\n"
Craig Tiller8c8d0aa2015-02-12 11:38:36 -0800679 " $Service$_method_names[$Idx$],\n"
yangg5bcea0d2015-01-06 10:35:03 -0800680 " ::grpc::RpcMethod::SERVER_STREAMING,\n"
Yang Gao1ff11f62015-01-14 11:45:32 -0800681 " new ::grpc::ServerStreamingHandler< "
nnobleebebb7e2014-12-10 16:31:01 -0800682 "$Service$::Service, $Request$, $Response$>(\n"
Yang Gao1ff11f62015-01-14 11:45:32 -0800683 " std::function< ::grpc::Status($Service$::Service*, "
yangga4b6f5d2014-12-17 15:53:12 -0800684 "::grpc::ServerContext*, "
Yang Gao1ff11f62015-01-14 11:45:32 -0800685 "const $Request$*, ::grpc::ServerWriter< $Response$>*)>("
nnobleebebb7e2014-12-10 16:31:01 -0800686 "&$Service$::Service::$Method$), this),\n"
687 " new $Request$, new $Response$));\n");
688 } else if (BidiStreaming(method)) {
689 printer->Print(
690 *vars,
691 "service_->AddMethod(new ::grpc::RpcServiceMethod(\n"
Craig Tiller8c8d0aa2015-02-12 11:38:36 -0800692 " $Service$_method_names[$Idx$],\n"
yangg5bcea0d2015-01-06 10:35:03 -0800693 " ::grpc::RpcMethod::BIDI_STREAMING,\n"
Yang Gao1ff11f62015-01-14 11:45:32 -0800694 " new ::grpc::BidiStreamingHandler< "
nnobleebebb7e2014-12-10 16:31:01 -0800695 "$Service$::Service, $Request$, $Response$>(\n"
Yang Gao1ff11f62015-01-14 11:45:32 -0800696 " std::function< ::grpc::Status($Service$::Service*, "
yangga4b6f5d2014-12-17 15:53:12 -0800697 "::grpc::ServerContext*, "
Yang Gao1ff11f62015-01-14 11:45:32 -0800698 "::grpc::ServerReaderWriter< $Response$, $Request$>*)>("
nnobleebebb7e2014-12-10 16:31:01 -0800699 "&$Service$::Service::$Method$), this),\n"
700 " new $Request$, new $Response$));\n");
701 }
702 }
703 printer->Print("return service_;\n");
704 printer->Outdent();
705 printer->Print("}\n\n");
706}
707
Craig Tillerecd49342015-01-18 14:36:47 -0800708std::string GetSourceServices(const google::protobuf::FileDescriptor *file) {
Nicolas Noblef5c5d802015-01-15 16:36:13 -0800709 std::string output;
nnobleebebb7e2014-12-10 16:31:01 -0800710 google::protobuf::io::StringOutputStream output_stream(&output);
711 google::protobuf::io::Printer printer(&output_stream, '$');
Nicolas Noblef5c5d802015-01-15 16:36:13 -0800712 std::map<std::string, std::string> vars;
yangg5bcea0d2015-01-06 10:35:03 -0800713 // Package string is empty or ends with a dot. It is used to fully qualify
714 // method names.
715 vars["Package"] = file->package();
716 if (!file->package().empty()) {
717 vars["Package"].append(".");
718 }
nnobleebebb7e2014-12-10 16:31:01 -0800719
720 for (int i = 0; i < file->service_count(); ++i) {
samuelwca9f3592014-12-15 14:22:04 -0800721 PrintSourceService(&printer, file->service(i), &vars);
nnobleebebb7e2014-12-10 16:31:01 -0800722 printer.Print("\n");
723 }
724 return output;
725}
726
Craig Tiller190d3602015-02-18 09:23:38 -0800727} // namespace grpc_cpp_generator