xref: /aosp_15_r20/external/grpc-grpc/src/compiler/csharp_generator.cc (revision cc02d7e222339f7a4f6ba5f422e6413f4bd931f2)
1*cc02d7e2SAndroid Build Coastguard Worker /*
2*cc02d7e2SAndroid Build Coastguard Worker  *
3*cc02d7e2SAndroid Build Coastguard Worker  * Copyright 2015 gRPC authors.
4*cc02d7e2SAndroid Build Coastguard Worker  *
5*cc02d7e2SAndroid Build Coastguard Worker  * Licensed under the Apache License, Version 2.0 (the "License");
6*cc02d7e2SAndroid Build Coastguard Worker  * you may not use this file except in compliance with the License.
7*cc02d7e2SAndroid Build Coastguard Worker  * You may obtain a copy of the License at
8*cc02d7e2SAndroid Build Coastguard Worker  *
9*cc02d7e2SAndroid Build Coastguard Worker  *     http://www.apache.org/licenses/LICENSE-2.0
10*cc02d7e2SAndroid Build Coastguard Worker  *
11*cc02d7e2SAndroid Build Coastguard Worker  * Unless required by applicable law or agreed to in writing, software
12*cc02d7e2SAndroid Build Coastguard Worker  * distributed under the License is distributed on an "AS IS" BASIS,
13*cc02d7e2SAndroid Build Coastguard Worker  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14*cc02d7e2SAndroid Build Coastguard Worker  * See the License for the specific language governing permissions and
15*cc02d7e2SAndroid Build Coastguard Worker  * limitations under the License.
16*cc02d7e2SAndroid Build Coastguard Worker  *
17*cc02d7e2SAndroid Build Coastguard Worker  */
18*cc02d7e2SAndroid Build Coastguard Worker 
19*cc02d7e2SAndroid Build Coastguard Worker #include "src/compiler/csharp_generator.h"
20*cc02d7e2SAndroid Build Coastguard Worker 
21*cc02d7e2SAndroid Build Coastguard Worker #include <cctype>
22*cc02d7e2SAndroid Build Coastguard Worker #include <map>
23*cc02d7e2SAndroid Build Coastguard Worker #include <sstream>
24*cc02d7e2SAndroid Build Coastguard Worker #include <vector>
25*cc02d7e2SAndroid Build Coastguard Worker 
26*cc02d7e2SAndroid Build Coastguard Worker #include "src/compiler/config.h"
27*cc02d7e2SAndroid Build Coastguard Worker #include "src/compiler/csharp_generator_helpers.h"
28*cc02d7e2SAndroid Build Coastguard Worker 
29*cc02d7e2SAndroid Build Coastguard Worker using grpc::protobuf::Descriptor;
30*cc02d7e2SAndroid Build Coastguard Worker using grpc::protobuf::FileDescriptor;
31*cc02d7e2SAndroid Build Coastguard Worker using grpc::protobuf::MethodDescriptor;
32*cc02d7e2SAndroid Build Coastguard Worker using grpc::protobuf::ServiceDescriptor;
33*cc02d7e2SAndroid Build Coastguard Worker using grpc::protobuf::io::Printer;
34*cc02d7e2SAndroid Build Coastguard Worker using grpc::protobuf::io::StringOutputStream;
35*cc02d7e2SAndroid Build Coastguard Worker using grpc_generator::StringReplace;
36*cc02d7e2SAndroid Build Coastguard Worker using std::vector;
37*cc02d7e2SAndroid Build Coastguard Worker 
38*cc02d7e2SAndroid Build Coastguard Worker namespace grpc_csharp_generator {
39*cc02d7e2SAndroid Build Coastguard Worker namespace {
40*cc02d7e2SAndroid Build Coastguard Worker 
41*cc02d7e2SAndroid Build Coastguard Worker // This function is a massaged version of
42*cc02d7e2SAndroid Build Coastguard Worker // https://github.com/protocolbuffers/protobuf/blob/master/src/google/protobuf/compiler/csharp/csharp_doc_comment.cc
43*cc02d7e2SAndroid Build Coastguard Worker // Currently, we cannot easily reuse the functionality as
44*cc02d7e2SAndroid Build Coastguard Worker // google/protobuf/compiler/csharp/csharp_doc_comment.h is not a public header.
45*cc02d7e2SAndroid Build Coastguard Worker // TODO(jtattermusch): reuse the functionality from google/protobuf.
GenerateDocCommentBodyImpl(grpc::protobuf::io::Printer * printer,grpc::protobuf::SourceLocation location)46*cc02d7e2SAndroid Build Coastguard Worker bool GenerateDocCommentBodyImpl(grpc::protobuf::io::Printer* printer,
47*cc02d7e2SAndroid Build Coastguard Worker                                 grpc::protobuf::SourceLocation location) {
48*cc02d7e2SAndroid Build Coastguard Worker   std::string comments = location.leading_comments.empty()
49*cc02d7e2SAndroid Build Coastguard Worker                              ? location.trailing_comments
50*cc02d7e2SAndroid Build Coastguard Worker                              : location.leading_comments;
51*cc02d7e2SAndroid Build Coastguard Worker   if (comments.empty()) {
52*cc02d7e2SAndroid Build Coastguard Worker     return false;
53*cc02d7e2SAndroid Build Coastguard Worker   }
54*cc02d7e2SAndroid Build Coastguard Worker   // XML escaping... no need for apostrophes etc as the whole text is going to
55*cc02d7e2SAndroid Build Coastguard Worker   // be a child
56*cc02d7e2SAndroid Build Coastguard Worker   // node of a summary element, not part of an attribute.
57*cc02d7e2SAndroid Build Coastguard Worker   comments = grpc_generator::StringReplace(comments, "&", "&amp;", true);
58*cc02d7e2SAndroid Build Coastguard Worker   comments = grpc_generator::StringReplace(comments, "<", "&lt;", true);
59*cc02d7e2SAndroid Build Coastguard Worker 
60*cc02d7e2SAndroid Build Coastguard Worker   std::vector<std::string> lines;
61*cc02d7e2SAndroid Build Coastguard Worker   grpc_generator::Split(comments, '\n', &lines);
62*cc02d7e2SAndroid Build Coastguard Worker   // TODO: We really should work out which part to put in the summary and which
63*cc02d7e2SAndroid Build Coastguard Worker   // to put in the remarks...
64*cc02d7e2SAndroid Build Coastguard Worker   // but that needs to be part of a bigger effort to understand the markdown
65*cc02d7e2SAndroid Build Coastguard Worker   // better anyway.
66*cc02d7e2SAndroid Build Coastguard Worker   printer->Print("/// <summary>\n");
67*cc02d7e2SAndroid Build Coastguard Worker   bool last_was_empty = false;
68*cc02d7e2SAndroid Build Coastguard Worker   // We squash multiple blank lines down to one, and remove any trailing blank
69*cc02d7e2SAndroid Build Coastguard Worker   // lines. We need
70*cc02d7e2SAndroid Build Coastguard Worker   // to preserve the blank lines themselves, as this is relevant in the
71*cc02d7e2SAndroid Build Coastguard Worker   // markdown.
72*cc02d7e2SAndroid Build Coastguard Worker   // Note that we can't remove leading or trailing whitespace as *that's*
73*cc02d7e2SAndroid Build Coastguard Worker   // relevant in markdown too.
74*cc02d7e2SAndroid Build Coastguard Worker   // (We don't skip "just whitespace" lines, either.)
75*cc02d7e2SAndroid Build Coastguard Worker   for (std::vector<std::string>::iterator it = lines.begin(); it != lines.end();
76*cc02d7e2SAndroid Build Coastguard Worker        ++it) {
77*cc02d7e2SAndroid Build Coastguard Worker     std::string line = *it;
78*cc02d7e2SAndroid Build Coastguard Worker     if (line.empty()) {
79*cc02d7e2SAndroid Build Coastguard Worker       last_was_empty = true;
80*cc02d7e2SAndroid Build Coastguard Worker     } else {
81*cc02d7e2SAndroid Build Coastguard Worker       if (last_was_empty) {
82*cc02d7e2SAndroid Build Coastguard Worker         printer->Print("///\n");
83*cc02d7e2SAndroid Build Coastguard Worker       }
84*cc02d7e2SAndroid Build Coastguard Worker       last_was_empty = false;
85*cc02d7e2SAndroid Build Coastguard Worker       // If the comment has an extra slash at the start then this can cause the
86*cc02d7e2SAndroid Build Coastguard Worker       // C# compiler to complain when generating the XML documentation Issue
87*cc02d7e2SAndroid Build Coastguard Worker       // [https://github.com/grpc/grpc/issues/35905](https://www.google.com/url?q=https://github.com/grpc/grpc/issues/35905&sa=D)
88*cc02d7e2SAndroid Build Coastguard Worker       if (line[0] == '/') {
89*cc02d7e2SAndroid Build Coastguard Worker         line.replace(0, 1, "&#x2F;");
90*cc02d7e2SAndroid Build Coastguard Worker       }
91*cc02d7e2SAndroid Build Coastguard Worker       printer->Print("///$line$\n", "line", line);
92*cc02d7e2SAndroid Build Coastguard Worker     }
93*cc02d7e2SAndroid Build Coastguard Worker   }
94*cc02d7e2SAndroid Build Coastguard Worker   printer->Print("/// </summary>\n");
95*cc02d7e2SAndroid Build Coastguard Worker   return true;
96*cc02d7e2SAndroid Build Coastguard Worker }
97*cc02d7e2SAndroid Build Coastguard Worker 
GenerateGeneratedCodeAttribute(grpc::protobuf::io::Printer * printer)98*cc02d7e2SAndroid Build Coastguard Worker void GenerateGeneratedCodeAttribute(grpc::protobuf::io::Printer* printer) {
99*cc02d7e2SAndroid Build Coastguard Worker   // Mark the code as generated using the [GeneratedCode] attribute.
100*cc02d7e2SAndroid Build Coastguard Worker   // We don't provide plugin version info in attribute the because:
101*cc02d7e2SAndroid Build Coastguard Worker   // * the version information is not readily available from the plugin's code.
102*cc02d7e2SAndroid Build Coastguard Worker   // * it would cause a lot of churn in the pre-generated code
103*cc02d7e2SAndroid Build Coastguard Worker   //   in this repository every time the version is updated.
104*cc02d7e2SAndroid Build Coastguard Worker   printer->Print(
105*cc02d7e2SAndroid Build Coastguard Worker       "[global::System.CodeDom.Compiler.GeneratedCode(\"grpc_csharp_plugin\", "
106*cc02d7e2SAndroid Build Coastguard Worker       "null)]\n");
107*cc02d7e2SAndroid Build Coastguard Worker }
108*cc02d7e2SAndroid Build Coastguard Worker 
GenerateObsoleteAttribute(grpc::protobuf::io::Printer * printer,bool is_deprecated)109*cc02d7e2SAndroid Build Coastguard Worker void GenerateObsoleteAttribute(grpc::protobuf::io::Printer* printer,
110*cc02d7e2SAndroid Build Coastguard Worker                                bool is_deprecated) {
111*cc02d7e2SAndroid Build Coastguard Worker   // Mark the code deprecated using the [ObsoleteAttribute] attribute.
112*cc02d7e2SAndroid Build Coastguard Worker   if (is_deprecated) {
113*cc02d7e2SAndroid Build Coastguard Worker     printer->Print("[global::System.ObsoleteAttribute]\n");
114*cc02d7e2SAndroid Build Coastguard Worker   }
115*cc02d7e2SAndroid Build Coastguard Worker }
116*cc02d7e2SAndroid Build Coastguard Worker 
117*cc02d7e2SAndroid Build Coastguard Worker template <typename DescriptorType>
GenerateDocCommentBody(grpc::protobuf::io::Printer * printer,const DescriptorType * descriptor)118*cc02d7e2SAndroid Build Coastguard Worker bool GenerateDocCommentBody(grpc::protobuf::io::Printer* printer,
119*cc02d7e2SAndroid Build Coastguard Worker                             const DescriptorType* descriptor) {
120*cc02d7e2SAndroid Build Coastguard Worker   grpc::protobuf::SourceLocation location;
121*cc02d7e2SAndroid Build Coastguard Worker   if (!descriptor->GetSourceLocation(&location)) {
122*cc02d7e2SAndroid Build Coastguard Worker     return false;
123*cc02d7e2SAndroid Build Coastguard Worker   }
124*cc02d7e2SAndroid Build Coastguard Worker   return GenerateDocCommentBodyImpl(printer, location);
125*cc02d7e2SAndroid Build Coastguard Worker }
126*cc02d7e2SAndroid Build Coastguard Worker 
GenerateDocCommentServerMethod(grpc::protobuf::io::Printer * printer,const MethodDescriptor * method)127*cc02d7e2SAndroid Build Coastguard Worker void GenerateDocCommentServerMethod(grpc::protobuf::io::Printer* printer,
128*cc02d7e2SAndroid Build Coastguard Worker                                     const MethodDescriptor* method) {
129*cc02d7e2SAndroid Build Coastguard Worker   if (GenerateDocCommentBody(printer, method)) {
130*cc02d7e2SAndroid Build Coastguard Worker     if (method->client_streaming()) {
131*cc02d7e2SAndroid Build Coastguard Worker       printer->Print(
132*cc02d7e2SAndroid Build Coastguard Worker           "/// <param name=\"requestStream\">Used for reading requests from "
133*cc02d7e2SAndroid Build Coastguard Worker           "the client.</param>\n");
134*cc02d7e2SAndroid Build Coastguard Worker     } else {
135*cc02d7e2SAndroid Build Coastguard Worker       printer->Print(
136*cc02d7e2SAndroid Build Coastguard Worker           "/// <param name=\"request\">The request received from the "
137*cc02d7e2SAndroid Build Coastguard Worker           "client.</param>\n");
138*cc02d7e2SAndroid Build Coastguard Worker     }
139*cc02d7e2SAndroid Build Coastguard Worker     if (method->server_streaming()) {
140*cc02d7e2SAndroid Build Coastguard Worker       printer->Print(
141*cc02d7e2SAndroid Build Coastguard Worker           "/// <param name=\"responseStream\">Used for sending responses back "
142*cc02d7e2SAndroid Build Coastguard Worker           "to the client.</param>\n");
143*cc02d7e2SAndroid Build Coastguard Worker     }
144*cc02d7e2SAndroid Build Coastguard Worker     printer->Print(
145*cc02d7e2SAndroid Build Coastguard Worker         "/// <param name=\"context\">The context of the server-side call "
146*cc02d7e2SAndroid Build Coastguard Worker         "handler being invoked.</param>\n");
147*cc02d7e2SAndroid Build Coastguard Worker     if (method->server_streaming()) {
148*cc02d7e2SAndroid Build Coastguard Worker       printer->Print(
149*cc02d7e2SAndroid Build Coastguard Worker           "/// <returns>A task indicating completion of the "
150*cc02d7e2SAndroid Build Coastguard Worker           "handler.</returns>\n");
151*cc02d7e2SAndroid Build Coastguard Worker     } else {
152*cc02d7e2SAndroid Build Coastguard Worker       printer->Print(
153*cc02d7e2SAndroid Build Coastguard Worker           "/// <returns>The response to send back to the client (wrapped by a "
154*cc02d7e2SAndroid Build Coastguard Worker           "task).</returns>\n");
155*cc02d7e2SAndroid Build Coastguard Worker     }
156*cc02d7e2SAndroid Build Coastguard Worker   }
157*cc02d7e2SAndroid Build Coastguard Worker }
158*cc02d7e2SAndroid Build Coastguard Worker 
GenerateDocCommentClientMethod(grpc::protobuf::io::Printer * printer,const MethodDescriptor * method,bool is_sync,bool use_call_options)159*cc02d7e2SAndroid Build Coastguard Worker void GenerateDocCommentClientMethod(grpc::protobuf::io::Printer* printer,
160*cc02d7e2SAndroid Build Coastguard Worker                                     const MethodDescriptor* method,
161*cc02d7e2SAndroid Build Coastguard Worker                                     bool is_sync, bool use_call_options) {
162*cc02d7e2SAndroid Build Coastguard Worker   if (GenerateDocCommentBody(printer, method)) {
163*cc02d7e2SAndroid Build Coastguard Worker     if (!method->client_streaming()) {
164*cc02d7e2SAndroid Build Coastguard Worker       printer->Print(
165*cc02d7e2SAndroid Build Coastguard Worker           "/// <param name=\"request\">The request to send to the "
166*cc02d7e2SAndroid Build Coastguard Worker           "server.</param>\n");
167*cc02d7e2SAndroid Build Coastguard Worker     }
168*cc02d7e2SAndroid Build Coastguard Worker     if (!use_call_options) {
169*cc02d7e2SAndroid Build Coastguard Worker       printer->Print(
170*cc02d7e2SAndroid Build Coastguard Worker           "/// <param name=\"headers\">The initial metadata to send with the "
171*cc02d7e2SAndroid Build Coastguard Worker           "call. This parameter is optional.</param>\n");
172*cc02d7e2SAndroid Build Coastguard Worker       printer->Print(
173*cc02d7e2SAndroid Build Coastguard Worker           "/// <param name=\"deadline\">An optional deadline for the call. The "
174*cc02d7e2SAndroid Build Coastguard Worker           "call will be cancelled if deadline is hit.</param>\n");
175*cc02d7e2SAndroid Build Coastguard Worker       printer->Print(
176*cc02d7e2SAndroid Build Coastguard Worker           "/// <param name=\"cancellationToken\">An optional token for "
177*cc02d7e2SAndroid Build Coastguard Worker           "canceling the call.</param>\n");
178*cc02d7e2SAndroid Build Coastguard Worker     } else {
179*cc02d7e2SAndroid Build Coastguard Worker       printer->Print(
180*cc02d7e2SAndroid Build Coastguard Worker           "/// <param name=\"options\">The options for the call.</param>\n");
181*cc02d7e2SAndroid Build Coastguard Worker     }
182*cc02d7e2SAndroid Build Coastguard Worker     if (is_sync) {
183*cc02d7e2SAndroid Build Coastguard Worker       printer->Print(
184*cc02d7e2SAndroid Build Coastguard Worker           "/// <returns>The response received from the server.</returns>\n");
185*cc02d7e2SAndroid Build Coastguard Worker     } else {
186*cc02d7e2SAndroid Build Coastguard Worker       printer->Print("/// <returns>The call object.</returns>\n");
187*cc02d7e2SAndroid Build Coastguard Worker     }
188*cc02d7e2SAndroid Build Coastguard Worker   }
189*cc02d7e2SAndroid Build Coastguard Worker }
190*cc02d7e2SAndroid Build Coastguard Worker 
GetServiceClassName(const ServiceDescriptor * service)191*cc02d7e2SAndroid Build Coastguard Worker std::string GetServiceClassName(const ServiceDescriptor* service) {
192*cc02d7e2SAndroid Build Coastguard Worker   return service->name();
193*cc02d7e2SAndroid Build Coastguard Worker }
194*cc02d7e2SAndroid Build Coastguard Worker 
GetClientClassName(const ServiceDescriptor * service)195*cc02d7e2SAndroid Build Coastguard Worker std::string GetClientClassName(const ServiceDescriptor* service) {
196*cc02d7e2SAndroid Build Coastguard Worker   return service->name() + "Client";
197*cc02d7e2SAndroid Build Coastguard Worker }
198*cc02d7e2SAndroid Build Coastguard Worker 
GetServerClassName(const ServiceDescriptor * service)199*cc02d7e2SAndroid Build Coastguard Worker std::string GetServerClassName(const ServiceDescriptor* service) {
200*cc02d7e2SAndroid Build Coastguard Worker   return service->name() + "Base";
201*cc02d7e2SAndroid Build Coastguard Worker }
202*cc02d7e2SAndroid Build Coastguard Worker 
GetCSharpMethodType(const MethodDescriptor * method)203*cc02d7e2SAndroid Build Coastguard Worker std::string GetCSharpMethodType(const MethodDescriptor* method) {
204*cc02d7e2SAndroid Build Coastguard Worker   if (method->client_streaming()) {
205*cc02d7e2SAndroid Build Coastguard Worker     if (method->server_streaming()) {
206*cc02d7e2SAndroid Build Coastguard Worker       return "grpc::MethodType.DuplexStreaming";
207*cc02d7e2SAndroid Build Coastguard Worker     } else {
208*cc02d7e2SAndroid Build Coastguard Worker       return "grpc::MethodType.ClientStreaming";
209*cc02d7e2SAndroid Build Coastguard Worker     }
210*cc02d7e2SAndroid Build Coastguard Worker   } else {
211*cc02d7e2SAndroid Build Coastguard Worker     if (method->server_streaming()) {
212*cc02d7e2SAndroid Build Coastguard Worker       return "grpc::MethodType.ServerStreaming";
213*cc02d7e2SAndroid Build Coastguard Worker     } else {
214*cc02d7e2SAndroid Build Coastguard Worker       return "grpc::MethodType.Unary";
215*cc02d7e2SAndroid Build Coastguard Worker     }
216*cc02d7e2SAndroid Build Coastguard Worker   }
217*cc02d7e2SAndroid Build Coastguard Worker }
218*cc02d7e2SAndroid Build Coastguard Worker 
GetCSharpServerMethodType(const MethodDescriptor * method)219*cc02d7e2SAndroid Build Coastguard Worker std::string GetCSharpServerMethodType(const MethodDescriptor* method) {
220*cc02d7e2SAndroid Build Coastguard Worker   if (method->client_streaming()) {
221*cc02d7e2SAndroid Build Coastguard Worker     if (method->server_streaming()) {
222*cc02d7e2SAndroid Build Coastguard Worker       return "grpc::DuplexStreamingServerMethod";
223*cc02d7e2SAndroid Build Coastguard Worker     } else {
224*cc02d7e2SAndroid Build Coastguard Worker       return "grpc::ClientStreamingServerMethod";
225*cc02d7e2SAndroid Build Coastguard Worker     }
226*cc02d7e2SAndroid Build Coastguard Worker   } else {
227*cc02d7e2SAndroid Build Coastguard Worker     if (method->server_streaming()) {
228*cc02d7e2SAndroid Build Coastguard Worker       return "grpc::ServerStreamingServerMethod";
229*cc02d7e2SAndroid Build Coastguard Worker     } else {
230*cc02d7e2SAndroid Build Coastguard Worker       return "grpc::UnaryServerMethod";
231*cc02d7e2SAndroid Build Coastguard Worker     }
232*cc02d7e2SAndroid Build Coastguard Worker   }
233*cc02d7e2SAndroid Build Coastguard Worker }
234*cc02d7e2SAndroid Build Coastguard Worker 
GetServiceNameFieldName()235*cc02d7e2SAndroid Build Coastguard Worker std::string GetServiceNameFieldName() { return "__ServiceName"; }
236*cc02d7e2SAndroid Build Coastguard Worker 
GetMarshallerFieldName(const Descriptor * message)237*cc02d7e2SAndroid Build Coastguard Worker std::string GetMarshallerFieldName(const Descriptor* message) {
238*cc02d7e2SAndroid Build Coastguard Worker   return "__Marshaller_" +
239*cc02d7e2SAndroid Build Coastguard Worker          grpc_generator::StringReplace(message->full_name(), ".", "_", true);
240*cc02d7e2SAndroid Build Coastguard Worker }
241*cc02d7e2SAndroid Build Coastguard Worker 
GetMethodFieldName(const MethodDescriptor * method)242*cc02d7e2SAndroid Build Coastguard Worker std::string GetMethodFieldName(const MethodDescriptor* method) {
243*cc02d7e2SAndroid Build Coastguard Worker   return "__Method_" + method->name();
244*cc02d7e2SAndroid Build Coastguard Worker }
245*cc02d7e2SAndroid Build Coastguard Worker 
GetMethodRequestParamMaybe(const MethodDescriptor * method,bool invocation_param=false)246*cc02d7e2SAndroid Build Coastguard Worker std::string GetMethodRequestParamMaybe(const MethodDescriptor* method,
247*cc02d7e2SAndroid Build Coastguard Worker                                        bool invocation_param = false) {
248*cc02d7e2SAndroid Build Coastguard Worker   if (method->client_streaming()) {
249*cc02d7e2SAndroid Build Coastguard Worker     return "";
250*cc02d7e2SAndroid Build Coastguard Worker   }
251*cc02d7e2SAndroid Build Coastguard Worker   if (invocation_param) {
252*cc02d7e2SAndroid Build Coastguard Worker     return "request, ";
253*cc02d7e2SAndroid Build Coastguard Worker   }
254*cc02d7e2SAndroid Build Coastguard Worker   return GRPC_CUSTOM_CSHARP_GETCLASSNAME(method->input_type()) + " request, ";
255*cc02d7e2SAndroid Build Coastguard Worker }
256*cc02d7e2SAndroid Build Coastguard Worker 
GetAccessLevel(bool internal_access)257*cc02d7e2SAndroid Build Coastguard Worker std::string GetAccessLevel(bool internal_access) {
258*cc02d7e2SAndroid Build Coastguard Worker   return internal_access ? "internal" : "public";
259*cc02d7e2SAndroid Build Coastguard Worker }
260*cc02d7e2SAndroid Build Coastguard Worker 
GetMethodReturnTypeClient(const MethodDescriptor * method)261*cc02d7e2SAndroid Build Coastguard Worker std::string GetMethodReturnTypeClient(const MethodDescriptor* method) {
262*cc02d7e2SAndroid Build Coastguard Worker   if (method->client_streaming()) {
263*cc02d7e2SAndroid Build Coastguard Worker     if (method->server_streaming()) {
264*cc02d7e2SAndroid Build Coastguard Worker       return "grpc::AsyncDuplexStreamingCall<" +
265*cc02d7e2SAndroid Build Coastguard Worker              GRPC_CUSTOM_CSHARP_GETCLASSNAME(method->input_type()) + ", " +
266*cc02d7e2SAndroid Build Coastguard Worker              GRPC_CUSTOM_CSHARP_GETCLASSNAME(method->output_type()) + ">";
267*cc02d7e2SAndroid Build Coastguard Worker     } else {
268*cc02d7e2SAndroid Build Coastguard Worker       return "grpc::AsyncClientStreamingCall<" +
269*cc02d7e2SAndroid Build Coastguard Worker              GRPC_CUSTOM_CSHARP_GETCLASSNAME(method->input_type()) + ", " +
270*cc02d7e2SAndroid Build Coastguard Worker              GRPC_CUSTOM_CSHARP_GETCLASSNAME(method->output_type()) + ">";
271*cc02d7e2SAndroid Build Coastguard Worker     }
272*cc02d7e2SAndroid Build Coastguard Worker   } else {
273*cc02d7e2SAndroid Build Coastguard Worker     if (method->server_streaming()) {
274*cc02d7e2SAndroid Build Coastguard Worker       return "grpc::AsyncServerStreamingCall<" +
275*cc02d7e2SAndroid Build Coastguard Worker              GRPC_CUSTOM_CSHARP_GETCLASSNAME(method->output_type()) + ">";
276*cc02d7e2SAndroid Build Coastguard Worker     } else {
277*cc02d7e2SAndroid Build Coastguard Worker       return "grpc::AsyncUnaryCall<" +
278*cc02d7e2SAndroid Build Coastguard Worker              GRPC_CUSTOM_CSHARP_GETCLASSNAME(method->output_type()) + ">";
279*cc02d7e2SAndroid Build Coastguard Worker     }
280*cc02d7e2SAndroid Build Coastguard Worker   }
281*cc02d7e2SAndroid Build Coastguard Worker }
282*cc02d7e2SAndroid Build Coastguard Worker 
GetMethodRequestParamServer(const MethodDescriptor * method)283*cc02d7e2SAndroid Build Coastguard Worker std::string GetMethodRequestParamServer(const MethodDescriptor* method) {
284*cc02d7e2SAndroid Build Coastguard Worker   if (method->client_streaming()) {
285*cc02d7e2SAndroid Build Coastguard Worker     return "grpc::IAsyncStreamReader<" +
286*cc02d7e2SAndroid Build Coastguard Worker            GRPC_CUSTOM_CSHARP_GETCLASSNAME(method->input_type()) +
287*cc02d7e2SAndroid Build Coastguard Worker            "> requestStream";
288*cc02d7e2SAndroid Build Coastguard Worker   }
289*cc02d7e2SAndroid Build Coastguard Worker   return GRPC_CUSTOM_CSHARP_GETCLASSNAME(method->input_type()) + " request";
290*cc02d7e2SAndroid Build Coastguard Worker }
291*cc02d7e2SAndroid Build Coastguard Worker 
GetMethodReturnTypeServer(const MethodDescriptor * method)292*cc02d7e2SAndroid Build Coastguard Worker std::string GetMethodReturnTypeServer(const MethodDescriptor* method) {
293*cc02d7e2SAndroid Build Coastguard Worker   if (method->server_streaming()) {
294*cc02d7e2SAndroid Build Coastguard Worker     return "global::System.Threading.Tasks.Task";
295*cc02d7e2SAndroid Build Coastguard Worker   }
296*cc02d7e2SAndroid Build Coastguard Worker   return "global::System.Threading.Tasks.Task<" +
297*cc02d7e2SAndroid Build Coastguard Worker          GRPC_CUSTOM_CSHARP_GETCLASSNAME(method->output_type()) + ">";
298*cc02d7e2SAndroid Build Coastguard Worker }
299*cc02d7e2SAndroid Build Coastguard Worker 
GetMethodResponseStreamMaybe(const MethodDescriptor * method)300*cc02d7e2SAndroid Build Coastguard Worker std::string GetMethodResponseStreamMaybe(const MethodDescriptor* method) {
301*cc02d7e2SAndroid Build Coastguard Worker   if (method->server_streaming()) {
302*cc02d7e2SAndroid Build Coastguard Worker     return ", grpc::IServerStreamWriter<" +
303*cc02d7e2SAndroid Build Coastguard Worker            GRPC_CUSTOM_CSHARP_GETCLASSNAME(method->output_type()) +
304*cc02d7e2SAndroid Build Coastguard Worker            "> responseStream";
305*cc02d7e2SAndroid Build Coastguard Worker   }
306*cc02d7e2SAndroid Build Coastguard Worker   return "";
307*cc02d7e2SAndroid Build Coastguard Worker }
308*cc02d7e2SAndroid Build Coastguard Worker 
309*cc02d7e2SAndroid Build Coastguard Worker // Gets vector of all messages used as input or output types.
GetUsedMessages(const ServiceDescriptor * service)310*cc02d7e2SAndroid Build Coastguard Worker std::vector<const Descriptor*> GetUsedMessages(
311*cc02d7e2SAndroid Build Coastguard Worker     const ServiceDescriptor* service) {
312*cc02d7e2SAndroid Build Coastguard Worker   std::set<const Descriptor*> descriptor_set;
313*cc02d7e2SAndroid Build Coastguard Worker   std::vector<const Descriptor*>
314*cc02d7e2SAndroid Build Coastguard Worker       result;  // vector is to maintain stable ordering
315*cc02d7e2SAndroid Build Coastguard Worker   for (int i = 0; i < service->method_count(); i++) {
316*cc02d7e2SAndroid Build Coastguard Worker     const MethodDescriptor* method = service->method(i);
317*cc02d7e2SAndroid Build Coastguard Worker     if (descriptor_set.find(method->input_type()) == descriptor_set.end()) {
318*cc02d7e2SAndroid Build Coastguard Worker       descriptor_set.insert(method->input_type());
319*cc02d7e2SAndroid Build Coastguard Worker       result.push_back(method->input_type());
320*cc02d7e2SAndroid Build Coastguard Worker     }
321*cc02d7e2SAndroid Build Coastguard Worker     if (descriptor_set.find(method->output_type()) == descriptor_set.end()) {
322*cc02d7e2SAndroid Build Coastguard Worker       descriptor_set.insert(method->output_type());
323*cc02d7e2SAndroid Build Coastguard Worker       result.push_back(method->output_type());
324*cc02d7e2SAndroid Build Coastguard Worker     }
325*cc02d7e2SAndroid Build Coastguard Worker   }
326*cc02d7e2SAndroid Build Coastguard Worker   return result;
327*cc02d7e2SAndroid Build Coastguard Worker }
328*cc02d7e2SAndroid Build Coastguard Worker 
GenerateMarshallerFields(Printer * out,const ServiceDescriptor * service)329*cc02d7e2SAndroid Build Coastguard Worker void GenerateMarshallerFields(Printer* out, const ServiceDescriptor* service) {
330*cc02d7e2SAndroid Build Coastguard Worker   std::vector<const Descriptor*> used_messages = GetUsedMessages(service);
331*cc02d7e2SAndroid Build Coastguard Worker   if (used_messages.size() != 0) {
332*cc02d7e2SAndroid Build Coastguard Worker     // Generate static helper methods for serialization/deserialization
333*cc02d7e2SAndroid Build Coastguard Worker     GenerateGeneratedCodeAttribute(out);
334*cc02d7e2SAndroid Build Coastguard Worker     out->Print(
335*cc02d7e2SAndroid Build Coastguard Worker         "static void __Helper_SerializeMessage("
336*cc02d7e2SAndroid Build Coastguard Worker         "global::Google.Protobuf.IMessage message, "
337*cc02d7e2SAndroid Build Coastguard Worker         "grpc::SerializationContext context)\n"
338*cc02d7e2SAndroid Build Coastguard Worker         "{\n");
339*cc02d7e2SAndroid Build Coastguard Worker     out->Indent();
340*cc02d7e2SAndroid Build Coastguard Worker     out->Print(
341*cc02d7e2SAndroid Build Coastguard Worker         "#if !GRPC_DISABLE_PROTOBUF_BUFFER_SERIALIZATION\n"
342*cc02d7e2SAndroid Build Coastguard Worker         "if (message is global::Google.Protobuf.IBufferMessage)\n"
343*cc02d7e2SAndroid Build Coastguard Worker         "{\n");
344*cc02d7e2SAndroid Build Coastguard Worker     out->Indent();
345*cc02d7e2SAndroid Build Coastguard Worker     out->Print(
346*cc02d7e2SAndroid Build Coastguard Worker         "context.SetPayloadLength(message.CalculateSize());\n"
347*cc02d7e2SAndroid Build Coastguard Worker         "global::Google.Protobuf.MessageExtensions.WriteTo(message, "
348*cc02d7e2SAndroid Build Coastguard Worker         "context.GetBufferWriter());\n"
349*cc02d7e2SAndroid Build Coastguard Worker         "context.Complete();\n"
350*cc02d7e2SAndroid Build Coastguard Worker         "return;\n");
351*cc02d7e2SAndroid Build Coastguard Worker     out->Outdent();
352*cc02d7e2SAndroid Build Coastguard Worker     out->Print(
353*cc02d7e2SAndroid Build Coastguard Worker         "}\n"
354*cc02d7e2SAndroid Build Coastguard Worker         "#endif\n");
355*cc02d7e2SAndroid Build Coastguard Worker     out->Print(
356*cc02d7e2SAndroid Build Coastguard Worker         "context.Complete("
357*cc02d7e2SAndroid Build Coastguard Worker         "global::Google.Protobuf.MessageExtensions.ToByteArray(message));\n");
358*cc02d7e2SAndroid Build Coastguard Worker     out->Outdent();
359*cc02d7e2SAndroid Build Coastguard Worker     out->Print("}\n\n");
360*cc02d7e2SAndroid Build Coastguard Worker 
361*cc02d7e2SAndroid Build Coastguard Worker     GenerateGeneratedCodeAttribute(out);
362*cc02d7e2SAndroid Build Coastguard Worker     out->Print(
363*cc02d7e2SAndroid Build Coastguard Worker         "static class __Helper_MessageCache<T>\n"
364*cc02d7e2SAndroid Build Coastguard Worker         "{\n");
365*cc02d7e2SAndroid Build Coastguard Worker     out->Indent();
366*cc02d7e2SAndroid Build Coastguard Worker     out->Print(
367*cc02d7e2SAndroid Build Coastguard Worker         "public static readonly bool IsBufferMessage = "
368*cc02d7e2SAndroid Build Coastguard Worker         "global::System.Reflection.IntrospectionExtensions.GetTypeInfo(typeof("
369*cc02d7e2SAndroid Build Coastguard Worker         "global::Google.Protobuf.IBufferMessage)).IsAssignableFrom(typeof(T));"
370*cc02d7e2SAndroid Build Coastguard Worker         "\n");
371*cc02d7e2SAndroid Build Coastguard Worker     out->Outdent();
372*cc02d7e2SAndroid Build Coastguard Worker     out->Print("}\n\n");
373*cc02d7e2SAndroid Build Coastguard Worker 
374*cc02d7e2SAndroid Build Coastguard Worker     GenerateGeneratedCodeAttribute(out);
375*cc02d7e2SAndroid Build Coastguard Worker     out->Print(
376*cc02d7e2SAndroid Build Coastguard Worker         "static T __Helper_DeserializeMessage<T>("
377*cc02d7e2SAndroid Build Coastguard Worker         "grpc::DeserializationContext context, "
378*cc02d7e2SAndroid Build Coastguard Worker         "global::Google.Protobuf.MessageParser<T> parser) "
379*cc02d7e2SAndroid Build Coastguard Worker         "where T : global::Google.Protobuf.IMessage<T>\n"
380*cc02d7e2SAndroid Build Coastguard Worker         "{\n");
381*cc02d7e2SAndroid Build Coastguard Worker     out->Indent();
382*cc02d7e2SAndroid Build Coastguard Worker     out->Print(
383*cc02d7e2SAndroid Build Coastguard Worker         "#if !GRPC_DISABLE_PROTOBUF_BUFFER_SERIALIZATION\n"
384*cc02d7e2SAndroid Build Coastguard Worker         "if (__Helper_MessageCache<T>.IsBufferMessage)\n"
385*cc02d7e2SAndroid Build Coastguard Worker         "{\n");
386*cc02d7e2SAndroid Build Coastguard Worker     out->Indent();
387*cc02d7e2SAndroid Build Coastguard Worker     out->Print(
388*cc02d7e2SAndroid Build Coastguard Worker         "return parser.ParseFrom(context.PayloadAsReadOnlySequence());\n");
389*cc02d7e2SAndroid Build Coastguard Worker     out->Outdent();
390*cc02d7e2SAndroid Build Coastguard Worker     out->Print(
391*cc02d7e2SAndroid Build Coastguard Worker         "}\n"
392*cc02d7e2SAndroid Build Coastguard Worker         "#endif\n");
393*cc02d7e2SAndroid Build Coastguard Worker     out->Print("return parser.ParseFrom(context.PayloadAsNewBuffer());\n");
394*cc02d7e2SAndroid Build Coastguard Worker     out->Outdent();
395*cc02d7e2SAndroid Build Coastguard Worker     out->Print("}\n\n");
396*cc02d7e2SAndroid Build Coastguard Worker   }
397*cc02d7e2SAndroid Build Coastguard Worker 
398*cc02d7e2SAndroid Build Coastguard Worker   for (size_t i = 0; i < used_messages.size(); i++) {
399*cc02d7e2SAndroid Build Coastguard Worker     const Descriptor* message = used_messages[i];
400*cc02d7e2SAndroid Build Coastguard Worker     GenerateGeneratedCodeAttribute(out);
401*cc02d7e2SAndroid Build Coastguard Worker     out->Print(
402*cc02d7e2SAndroid Build Coastguard Worker         "static readonly grpc::Marshaller<$type$> $fieldname$ = "
403*cc02d7e2SAndroid Build Coastguard Worker         "grpc::Marshallers.Create(__Helper_SerializeMessage, "
404*cc02d7e2SAndroid Build Coastguard Worker         "context => __Helper_DeserializeMessage(context, $type$.Parser));\n",
405*cc02d7e2SAndroid Build Coastguard Worker         "fieldname", GetMarshallerFieldName(message), "type",
406*cc02d7e2SAndroid Build Coastguard Worker         GRPC_CUSTOM_CSHARP_GETCLASSNAME(message));
407*cc02d7e2SAndroid Build Coastguard Worker   }
408*cc02d7e2SAndroid Build Coastguard Worker   out->Print("\n");
409*cc02d7e2SAndroid Build Coastguard Worker }
410*cc02d7e2SAndroid Build Coastguard Worker 
GenerateStaticMethodField(Printer * out,const MethodDescriptor * method)411*cc02d7e2SAndroid Build Coastguard Worker void GenerateStaticMethodField(Printer* out, const MethodDescriptor* method) {
412*cc02d7e2SAndroid Build Coastguard Worker   GenerateGeneratedCodeAttribute(out);
413*cc02d7e2SAndroid Build Coastguard Worker   out->Print(
414*cc02d7e2SAndroid Build Coastguard Worker       "static readonly grpc::Method<$request$, $response$> $fieldname$ = new "
415*cc02d7e2SAndroid Build Coastguard Worker       "grpc::Method<$request$, $response$>(\n",
416*cc02d7e2SAndroid Build Coastguard Worker       "fieldname", GetMethodFieldName(method), "request",
417*cc02d7e2SAndroid Build Coastguard Worker       GRPC_CUSTOM_CSHARP_GETCLASSNAME(method->input_type()), "response",
418*cc02d7e2SAndroid Build Coastguard Worker       GRPC_CUSTOM_CSHARP_GETCLASSNAME(method->output_type()));
419*cc02d7e2SAndroid Build Coastguard Worker   out->Indent();
420*cc02d7e2SAndroid Build Coastguard Worker   out->Indent();
421*cc02d7e2SAndroid Build Coastguard Worker   out->Print("$methodtype$,\n", "methodtype", GetCSharpMethodType(method));
422*cc02d7e2SAndroid Build Coastguard Worker   out->Print("$servicenamefield$,\n", "servicenamefield",
423*cc02d7e2SAndroid Build Coastguard Worker              GetServiceNameFieldName());
424*cc02d7e2SAndroid Build Coastguard Worker   out->Print("\"$methodname$\",\n", "methodname", method->name());
425*cc02d7e2SAndroid Build Coastguard Worker   out->Print("$requestmarshaller$,\n", "requestmarshaller",
426*cc02d7e2SAndroid Build Coastguard Worker              GetMarshallerFieldName(method->input_type()));
427*cc02d7e2SAndroid Build Coastguard Worker   out->Print("$responsemarshaller$);\n", "responsemarshaller",
428*cc02d7e2SAndroid Build Coastguard Worker              GetMarshallerFieldName(method->output_type()));
429*cc02d7e2SAndroid Build Coastguard Worker   out->Print("\n");
430*cc02d7e2SAndroid Build Coastguard Worker   out->Outdent();
431*cc02d7e2SAndroid Build Coastguard Worker   out->Outdent();
432*cc02d7e2SAndroid Build Coastguard Worker }
433*cc02d7e2SAndroid Build Coastguard Worker 
GenerateServiceDescriptorProperty(Printer * out,const ServiceDescriptor * service)434*cc02d7e2SAndroid Build Coastguard Worker void GenerateServiceDescriptorProperty(Printer* out,
435*cc02d7e2SAndroid Build Coastguard Worker                                        const ServiceDescriptor* service) {
436*cc02d7e2SAndroid Build Coastguard Worker   std::ostringstream index;
437*cc02d7e2SAndroid Build Coastguard Worker   index << service->index();
438*cc02d7e2SAndroid Build Coastguard Worker   out->Print("/// <summary>Service descriptor</summary>\n");
439*cc02d7e2SAndroid Build Coastguard Worker   out->Print(
440*cc02d7e2SAndroid Build Coastguard Worker       "public static global::Google.Protobuf.Reflection.ServiceDescriptor "
441*cc02d7e2SAndroid Build Coastguard Worker       "Descriptor\n");
442*cc02d7e2SAndroid Build Coastguard Worker   out->Print("{\n");
443*cc02d7e2SAndroid Build Coastguard Worker   out->Print("  get { return $umbrella$.Descriptor.Services[$index$]; }\n",
444*cc02d7e2SAndroid Build Coastguard Worker              "umbrella",
445*cc02d7e2SAndroid Build Coastguard Worker              GRPC_CUSTOM_CSHARP_GETREFLECTIONCLASSNAME(service->file()),
446*cc02d7e2SAndroid Build Coastguard Worker              "index", index.str());
447*cc02d7e2SAndroid Build Coastguard Worker   out->Print("}\n");
448*cc02d7e2SAndroid Build Coastguard Worker   out->Print("\n");
449*cc02d7e2SAndroid Build Coastguard Worker }
450*cc02d7e2SAndroid Build Coastguard Worker 
GenerateServerClass(Printer * out,const ServiceDescriptor * service)451*cc02d7e2SAndroid Build Coastguard Worker void GenerateServerClass(Printer* out, const ServiceDescriptor* service) {
452*cc02d7e2SAndroid Build Coastguard Worker   out->Print(
453*cc02d7e2SAndroid Build Coastguard Worker       "/// <summary>Base class for server-side implementations of "
454*cc02d7e2SAndroid Build Coastguard Worker       "$servicename$</summary>\n",
455*cc02d7e2SAndroid Build Coastguard Worker       "servicename", GetServiceClassName(service));
456*cc02d7e2SAndroid Build Coastguard Worker   GenerateObsoleteAttribute(out, service->options().deprecated());
457*cc02d7e2SAndroid Build Coastguard Worker   out->Print(
458*cc02d7e2SAndroid Build Coastguard Worker       "[grpc::BindServiceMethod(typeof($classname$), "
459*cc02d7e2SAndroid Build Coastguard Worker       "\"BindService\")]\n",
460*cc02d7e2SAndroid Build Coastguard Worker       "classname", GetServiceClassName(service));
461*cc02d7e2SAndroid Build Coastguard Worker   out->Print("public abstract partial class $name$\n", "name",
462*cc02d7e2SAndroid Build Coastguard Worker              GetServerClassName(service));
463*cc02d7e2SAndroid Build Coastguard Worker   out->Print("{\n");
464*cc02d7e2SAndroid Build Coastguard Worker   out->Indent();
465*cc02d7e2SAndroid Build Coastguard Worker   for (int i = 0; i < service->method_count(); i++) {
466*cc02d7e2SAndroid Build Coastguard Worker     const MethodDescriptor* method = service->method(i);
467*cc02d7e2SAndroid Build Coastguard Worker     GenerateDocCommentServerMethod(out, method);
468*cc02d7e2SAndroid Build Coastguard Worker     GenerateObsoleteAttribute(out, method->options().deprecated());
469*cc02d7e2SAndroid Build Coastguard Worker     GenerateGeneratedCodeAttribute(out);
470*cc02d7e2SAndroid Build Coastguard Worker     out->Print(
471*cc02d7e2SAndroid Build Coastguard Worker         "public virtual $returntype$ "
472*cc02d7e2SAndroid Build Coastguard Worker         "$methodname$($request$$response_stream_maybe$, "
473*cc02d7e2SAndroid Build Coastguard Worker         "grpc::ServerCallContext context)\n",
474*cc02d7e2SAndroid Build Coastguard Worker         "methodname", method->name(), "returntype",
475*cc02d7e2SAndroid Build Coastguard Worker         GetMethodReturnTypeServer(method), "request",
476*cc02d7e2SAndroid Build Coastguard Worker         GetMethodRequestParamServer(method), "response_stream_maybe",
477*cc02d7e2SAndroid Build Coastguard Worker         GetMethodResponseStreamMaybe(method));
478*cc02d7e2SAndroid Build Coastguard Worker     out->Print("{\n");
479*cc02d7e2SAndroid Build Coastguard Worker     out->Indent();
480*cc02d7e2SAndroid Build Coastguard Worker     out->Print(
481*cc02d7e2SAndroid Build Coastguard Worker         "throw new grpc::RpcException("
482*cc02d7e2SAndroid Build Coastguard Worker         "new grpc::Status(grpc::StatusCode.Unimplemented, \"\"));\n");
483*cc02d7e2SAndroid Build Coastguard Worker     out->Outdent();
484*cc02d7e2SAndroid Build Coastguard Worker     out->Print("}\n\n");
485*cc02d7e2SAndroid Build Coastguard Worker   }
486*cc02d7e2SAndroid Build Coastguard Worker   out->Outdent();
487*cc02d7e2SAndroid Build Coastguard Worker   out->Print("}\n");
488*cc02d7e2SAndroid Build Coastguard Worker   out->Print("\n");
489*cc02d7e2SAndroid Build Coastguard Worker }
490*cc02d7e2SAndroid Build Coastguard Worker 
GenerateClientStub(Printer * out,const ServiceDescriptor * service)491*cc02d7e2SAndroid Build Coastguard Worker void GenerateClientStub(Printer* out, const ServiceDescriptor* service) {
492*cc02d7e2SAndroid Build Coastguard Worker   out->Print("/// <summary>Client for $servicename$</summary>\n", "servicename",
493*cc02d7e2SAndroid Build Coastguard Worker              GetServiceClassName(service));
494*cc02d7e2SAndroid Build Coastguard Worker   GenerateObsoleteAttribute(out, service->options().deprecated());
495*cc02d7e2SAndroid Build Coastguard Worker   out->Print("public partial class $name$ : grpc::ClientBase<$name$>\n", "name",
496*cc02d7e2SAndroid Build Coastguard Worker              GetClientClassName(service));
497*cc02d7e2SAndroid Build Coastguard Worker   out->Print("{\n");
498*cc02d7e2SAndroid Build Coastguard Worker   out->Indent();
499*cc02d7e2SAndroid Build Coastguard Worker 
500*cc02d7e2SAndroid Build Coastguard Worker   // constructors
501*cc02d7e2SAndroid Build Coastguard Worker   out->Print(
502*cc02d7e2SAndroid Build Coastguard Worker       "/// <summary>Creates a new client for $servicename$</summary>\n"
503*cc02d7e2SAndroid Build Coastguard Worker       "/// <param name=\"channel\">The channel to use to make remote "
504*cc02d7e2SAndroid Build Coastguard Worker       "calls.</param>\n",
505*cc02d7e2SAndroid Build Coastguard Worker       "servicename", GetServiceClassName(service));
506*cc02d7e2SAndroid Build Coastguard Worker   GenerateGeneratedCodeAttribute(out);
507*cc02d7e2SAndroid Build Coastguard Worker   out->Print("public $name$(grpc::ChannelBase channel) : base(channel)\n",
508*cc02d7e2SAndroid Build Coastguard Worker              "name", GetClientClassName(service));
509*cc02d7e2SAndroid Build Coastguard Worker   out->Print("{\n");
510*cc02d7e2SAndroid Build Coastguard Worker   out->Print("}\n");
511*cc02d7e2SAndroid Build Coastguard Worker   out->Print(
512*cc02d7e2SAndroid Build Coastguard Worker       "/// <summary>Creates a new client for $servicename$ that uses a custom "
513*cc02d7e2SAndroid Build Coastguard Worker       "<c>CallInvoker</c>.</summary>\n"
514*cc02d7e2SAndroid Build Coastguard Worker       "/// <param name=\"callInvoker\">The callInvoker to use to make remote "
515*cc02d7e2SAndroid Build Coastguard Worker       "calls.</param>\n",
516*cc02d7e2SAndroid Build Coastguard Worker       "servicename", GetServiceClassName(service));
517*cc02d7e2SAndroid Build Coastguard Worker   GenerateGeneratedCodeAttribute(out);
518*cc02d7e2SAndroid Build Coastguard Worker   out->Print(
519*cc02d7e2SAndroid Build Coastguard Worker       "public $name$(grpc::CallInvoker callInvoker) : base(callInvoker)\n",
520*cc02d7e2SAndroid Build Coastguard Worker       "name", GetClientClassName(service));
521*cc02d7e2SAndroid Build Coastguard Worker   out->Print("{\n");
522*cc02d7e2SAndroid Build Coastguard Worker   out->Print("}\n");
523*cc02d7e2SAndroid Build Coastguard Worker   out->Print(
524*cc02d7e2SAndroid Build Coastguard Worker       "/// <summary>Protected parameterless constructor to allow creation"
525*cc02d7e2SAndroid Build Coastguard Worker       " of test doubles.</summary>\n");
526*cc02d7e2SAndroid Build Coastguard Worker   GenerateGeneratedCodeAttribute(out);
527*cc02d7e2SAndroid Build Coastguard Worker   out->Print("protected $name$() : base()\n", "name",
528*cc02d7e2SAndroid Build Coastguard Worker              GetClientClassName(service));
529*cc02d7e2SAndroid Build Coastguard Worker   out->Print("{\n");
530*cc02d7e2SAndroid Build Coastguard Worker   out->Print("}\n");
531*cc02d7e2SAndroid Build Coastguard Worker   out->Print(
532*cc02d7e2SAndroid Build Coastguard Worker       "/// <summary>Protected constructor to allow creation of configured "
533*cc02d7e2SAndroid Build Coastguard Worker       "clients.</summary>\n"
534*cc02d7e2SAndroid Build Coastguard Worker       "/// <param name=\"configuration\">The client configuration.</param>\n");
535*cc02d7e2SAndroid Build Coastguard Worker   GenerateGeneratedCodeAttribute(out);
536*cc02d7e2SAndroid Build Coastguard Worker   out->Print(
537*cc02d7e2SAndroid Build Coastguard Worker       "protected $name$(ClientBaseConfiguration configuration)"
538*cc02d7e2SAndroid Build Coastguard Worker       " : base(configuration)\n",
539*cc02d7e2SAndroid Build Coastguard Worker       "name", GetClientClassName(service));
540*cc02d7e2SAndroid Build Coastguard Worker   out->Print("{\n");
541*cc02d7e2SAndroid Build Coastguard Worker   out->Print("}\n\n");
542*cc02d7e2SAndroid Build Coastguard Worker 
543*cc02d7e2SAndroid Build Coastguard Worker   for (int i = 0; i < service->method_count(); i++) {
544*cc02d7e2SAndroid Build Coastguard Worker     const MethodDescriptor* method = service->method(i);
545*cc02d7e2SAndroid Build Coastguard Worker     const bool is_deprecated = method->options().deprecated();
546*cc02d7e2SAndroid Build Coastguard Worker     if (!method->client_streaming() && !method->server_streaming()) {
547*cc02d7e2SAndroid Build Coastguard Worker       // unary calls have an extra synchronous stub method
548*cc02d7e2SAndroid Build Coastguard Worker       GenerateDocCommentClientMethod(out, method, true, false);
549*cc02d7e2SAndroid Build Coastguard Worker       GenerateObsoleteAttribute(out, is_deprecated);
550*cc02d7e2SAndroid Build Coastguard Worker       GenerateGeneratedCodeAttribute(out);
551*cc02d7e2SAndroid Build Coastguard Worker       out->Print(
552*cc02d7e2SAndroid Build Coastguard Worker           "public virtual $response$ $methodname$($request$ request, "
553*cc02d7e2SAndroid Build Coastguard Worker           "grpc::Metadata "
554*cc02d7e2SAndroid Build Coastguard Worker           "headers = null, global::System.DateTime? deadline = null, "
555*cc02d7e2SAndroid Build Coastguard Worker           "global::System.Threading.CancellationToken "
556*cc02d7e2SAndroid Build Coastguard Worker           "cancellationToken = "
557*cc02d7e2SAndroid Build Coastguard Worker           "default(global::System.Threading.CancellationToken))\n",
558*cc02d7e2SAndroid Build Coastguard Worker           "methodname", method->name(), "request",
559*cc02d7e2SAndroid Build Coastguard Worker           GRPC_CUSTOM_CSHARP_GETCLASSNAME(method->input_type()), "response",
560*cc02d7e2SAndroid Build Coastguard Worker           GRPC_CUSTOM_CSHARP_GETCLASSNAME(method->output_type()));
561*cc02d7e2SAndroid Build Coastguard Worker       out->Print("{\n");
562*cc02d7e2SAndroid Build Coastguard Worker       out->Indent();
563*cc02d7e2SAndroid Build Coastguard Worker       out->Print(
564*cc02d7e2SAndroid Build Coastguard Worker           "return $methodname$(request, new grpc::CallOptions(headers, "
565*cc02d7e2SAndroid Build Coastguard Worker           "deadline, "
566*cc02d7e2SAndroid Build Coastguard Worker           "cancellationToken));\n",
567*cc02d7e2SAndroid Build Coastguard Worker           "methodname", method->name());
568*cc02d7e2SAndroid Build Coastguard Worker       out->Outdent();
569*cc02d7e2SAndroid Build Coastguard Worker       out->Print("}\n");
570*cc02d7e2SAndroid Build Coastguard Worker 
571*cc02d7e2SAndroid Build Coastguard Worker       // overload taking CallOptions as a param
572*cc02d7e2SAndroid Build Coastguard Worker       GenerateDocCommentClientMethod(out, method, true, true);
573*cc02d7e2SAndroid Build Coastguard Worker       GenerateObsoleteAttribute(out, is_deprecated);
574*cc02d7e2SAndroid Build Coastguard Worker       GenerateGeneratedCodeAttribute(out);
575*cc02d7e2SAndroid Build Coastguard Worker       out->Print(
576*cc02d7e2SAndroid Build Coastguard Worker           "public virtual $response$ $methodname$($request$ request, "
577*cc02d7e2SAndroid Build Coastguard Worker           "grpc::CallOptions options)\n",
578*cc02d7e2SAndroid Build Coastguard Worker           "methodname", method->name(), "request",
579*cc02d7e2SAndroid Build Coastguard Worker           GRPC_CUSTOM_CSHARP_GETCLASSNAME(method->input_type()), "response",
580*cc02d7e2SAndroid Build Coastguard Worker           GRPC_CUSTOM_CSHARP_GETCLASSNAME(method->output_type()));
581*cc02d7e2SAndroid Build Coastguard Worker       out->Print("{\n");
582*cc02d7e2SAndroid Build Coastguard Worker       out->Indent();
583*cc02d7e2SAndroid Build Coastguard Worker       out->Print(
584*cc02d7e2SAndroid Build Coastguard Worker           "return CallInvoker.BlockingUnaryCall($methodfield$, null, options, "
585*cc02d7e2SAndroid Build Coastguard Worker           "request);\n",
586*cc02d7e2SAndroid Build Coastguard Worker           "methodfield", GetMethodFieldName(method));
587*cc02d7e2SAndroid Build Coastguard Worker       out->Outdent();
588*cc02d7e2SAndroid Build Coastguard Worker       out->Print("}\n");
589*cc02d7e2SAndroid Build Coastguard Worker     }
590*cc02d7e2SAndroid Build Coastguard Worker 
591*cc02d7e2SAndroid Build Coastguard Worker     std::string method_name = method->name();
592*cc02d7e2SAndroid Build Coastguard Worker     if (!method->client_streaming() && !method->server_streaming()) {
593*cc02d7e2SAndroid Build Coastguard Worker       method_name += "Async";  // prevent name clash with synchronous method.
594*cc02d7e2SAndroid Build Coastguard Worker     }
595*cc02d7e2SAndroid Build Coastguard Worker     GenerateDocCommentClientMethod(out, method, false, false);
596*cc02d7e2SAndroid Build Coastguard Worker     GenerateObsoleteAttribute(out, is_deprecated);
597*cc02d7e2SAndroid Build Coastguard Worker     GenerateGeneratedCodeAttribute(out);
598*cc02d7e2SAndroid Build Coastguard Worker     out->Print(
599*cc02d7e2SAndroid Build Coastguard Worker         "public virtual $returntype$ "
600*cc02d7e2SAndroid Build Coastguard Worker         "$methodname$($request_maybe$grpc::Metadata "
601*cc02d7e2SAndroid Build Coastguard Worker         "headers = null, global::System.DateTime? deadline = null, "
602*cc02d7e2SAndroid Build Coastguard Worker         "global::System.Threading.CancellationToken "
603*cc02d7e2SAndroid Build Coastguard Worker         "cancellationToken = "
604*cc02d7e2SAndroid Build Coastguard Worker         "default(global::System.Threading.CancellationToken))\n",
605*cc02d7e2SAndroid Build Coastguard Worker         "methodname", method_name, "request_maybe",
606*cc02d7e2SAndroid Build Coastguard Worker         GetMethodRequestParamMaybe(method), "returntype",
607*cc02d7e2SAndroid Build Coastguard Worker         GetMethodReturnTypeClient(method));
608*cc02d7e2SAndroid Build Coastguard Worker     out->Print("{\n");
609*cc02d7e2SAndroid Build Coastguard Worker     out->Indent();
610*cc02d7e2SAndroid Build Coastguard Worker 
611*cc02d7e2SAndroid Build Coastguard Worker     out->Print(
612*cc02d7e2SAndroid Build Coastguard Worker         "return $methodname$($request_maybe$new grpc::CallOptions(headers, "
613*cc02d7e2SAndroid Build Coastguard Worker         "deadline, "
614*cc02d7e2SAndroid Build Coastguard Worker         "cancellationToken));\n",
615*cc02d7e2SAndroid Build Coastguard Worker         "methodname", method_name, "request_maybe",
616*cc02d7e2SAndroid Build Coastguard Worker         GetMethodRequestParamMaybe(method, true));
617*cc02d7e2SAndroid Build Coastguard Worker     out->Outdent();
618*cc02d7e2SAndroid Build Coastguard Worker     out->Print("}\n");
619*cc02d7e2SAndroid Build Coastguard Worker 
620*cc02d7e2SAndroid Build Coastguard Worker     // overload taking CallOptions as a param
621*cc02d7e2SAndroid Build Coastguard Worker     GenerateDocCommentClientMethod(out, method, false, true);
622*cc02d7e2SAndroid Build Coastguard Worker     GenerateObsoleteAttribute(out, is_deprecated);
623*cc02d7e2SAndroid Build Coastguard Worker     GenerateGeneratedCodeAttribute(out);
624*cc02d7e2SAndroid Build Coastguard Worker     out->Print(
625*cc02d7e2SAndroid Build Coastguard Worker         "public virtual $returntype$ "
626*cc02d7e2SAndroid Build Coastguard Worker         "$methodname$($request_maybe$grpc::CallOptions "
627*cc02d7e2SAndroid Build Coastguard Worker         "options)\n",
628*cc02d7e2SAndroid Build Coastguard Worker         "methodname", method_name, "request_maybe",
629*cc02d7e2SAndroid Build Coastguard Worker         GetMethodRequestParamMaybe(method), "returntype",
630*cc02d7e2SAndroid Build Coastguard Worker         GetMethodReturnTypeClient(method));
631*cc02d7e2SAndroid Build Coastguard Worker     out->Print("{\n");
632*cc02d7e2SAndroid Build Coastguard Worker     out->Indent();
633*cc02d7e2SAndroid Build Coastguard Worker     if (!method->client_streaming() && !method->server_streaming()) {
634*cc02d7e2SAndroid Build Coastguard Worker       // Non-Streaming
635*cc02d7e2SAndroid Build Coastguard Worker       out->Print(
636*cc02d7e2SAndroid Build Coastguard Worker           "return CallInvoker.AsyncUnaryCall($methodfield$, null, options, "
637*cc02d7e2SAndroid Build Coastguard Worker           "request);\n",
638*cc02d7e2SAndroid Build Coastguard Worker           "methodfield", GetMethodFieldName(method));
639*cc02d7e2SAndroid Build Coastguard Worker     } else if (method->client_streaming() && !method->server_streaming()) {
640*cc02d7e2SAndroid Build Coastguard Worker       // Client Streaming Only
641*cc02d7e2SAndroid Build Coastguard Worker       out->Print(
642*cc02d7e2SAndroid Build Coastguard Worker           "return CallInvoker.AsyncClientStreamingCall($methodfield$, null, "
643*cc02d7e2SAndroid Build Coastguard Worker           "options);\n",
644*cc02d7e2SAndroid Build Coastguard Worker           "methodfield", GetMethodFieldName(method));
645*cc02d7e2SAndroid Build Coastguard Worker     } else if (!method->client_streaming() && method->server_streaming()) {
646*cc02d7e2SAndroid Build Coastguard Worker       // Server Streaming Only
647*cc02d7e2SAndroid Build Coastguard Worker       out->Print(
648*cc02d7e2SAndroid Build Coastguard Worker           "return CallInvoker.AsyncServerStreamingCall($methodfield$, null, "
649*cc02d7e2SAndroid Build Coastguard Worker           "options, request);\n",
650*cc02d7e2SAndroid Build Coastguard Worker           "methodfield", GetMethodFieldName(method));
651*cc02d7e2SAndroid Build Coastguard Worker     } else {
652*cc02d7e2SAndroid Build Coastguard Worker       // Bi-Directional Streaming
653*cc02d7e2SAndroid Build Coastguard Worker       out->Print(
654*cc02d7e2SAndroid Build Coastguard Worker           "return CallInvoker.AsyncDuplexStreamingCall($methodfield$, null, "
655*cc02d7e2SAndroid Build Coastguard Worker           "options);\n",
656*cc02d7e2SAndroid Build Coastguard Worker           "methodfield", GetMethodFieldName(method));
657*cc02d7e2SAndroid Build Coastguard Worker     }
658*cc02d7e2SAndroid Build Coastguard Worker     out->Outdent();
659*cc02d7e2SAndroid Build Coastguard Worker     out->Print("}\n");
660*cc02d7e2SAndroid Build Coastguard Worker   }
661*cc02d7e2SAndroid Build Coastguard Worker 
662*cc02d7e2SAndroid Build Coastguard Worker   // override NewInstance method
663*cc02d7e2SAndroid Build Coastguard Worker   out->Print(
664*cc02d7e2SAndroid Build Coastguard Worker       "/// <summary>Creates a new instance of client from given "
665*cc02d7e2SAndroid Build Coastguard Worker       "<c>ClientBaseConfiguration</c>.</summary>\n");
666*cc02d7e2SAndroid Build Coastguard Worker   GenerateGeneratedCodeAttribute(out);
667*cc02d7e2SAndroid Build Coastguard Worker   out->Print(
668*cc02d7e2SAndroid Build Coastguard Worker       "protected override $name$ NewInstance(ClientBaseConfiguration "
669*cc02d7e2SAndroid Build Coastguard Worker       "configuration)\n",
670*cc02d7e2SAndroid Build Coastguard Worker       "name", GetClientClassName(service));
671*cc02d7e2SAndroid Build Coastguard Worker   out->Print("{\n");
672*cc02d7e2SAndroid Build Coastguard Worker   out->Indent();
673*cc02d7e2SAndroid Build Coastguard Worker   out->Print("return new $name$(configuration);\n", "name",
674*cc02d7e2SAndroid Build Coastguard Worker              GetClientClassName(service));
675*cc02d7e2SAndroid Build Coastguard Worker   out->Outdent();
676*cc02d7e2SAndroid Build Coastguard Worker   out->Print("}\n");
677*cc02d7e2SAndroid Build Coastguard Worker 
678*cc02d7e2SAndroid Build Coastguard Worker   out->Outdent();
679*cc02d7e2SAndroid Build Coastguard Worker   out->Print("}\n");
680*cc02d7e2SAndroid Build Coastguard Worker   out->Print("\n");
681*cc02d7e2SAndroid Build Coastguard Worker }
682*cc02d7e2SAndroid Build Coastguard Worker 
GenerateBindServiceMethod(Printer * out,const ServiceDescriptor * service)683*cc02d7e2SAndroid Build Coastguard Worker void GenerateBindServiceMethod(Printer* out, const ServiceDescriptor* service) {
684*cc02d7e2SAndroid Build Coastguard Worker   out->Print(
685*cc02d7e2SAndroid Build Coastguard Worker       "/// <summary>Creates service definition that can be registered with a "
686*cc02d7e2SAndroid Build Coastguard Worker       "server</summary>\n");
687*cc02d7e2SAndroid Build Coastguard Worker   out->Print(
688*cc02d7e2SAndroid Build Coastguard Worker       "/// <param name=\"serviceImpl\">An object implementing the server-side"
689*cc02d7e2SAndroid Build Coastguard Worker       " handling logic.</param>\n");
690*cc02d7e2SAndroid Build Coastguard Worker   GenerateGeneratedCodeAttribute(out);
691*cc02d7e2SAndroid Build Coastguard Worker   out->Print(
692*cc02d7e2SAndroid Build Coastguard Worker       "public static grpc::ServerServiceDefinition BindService($implclass$ "
693*cc02d7e2SAndroid Build Coastguard Worker       "serviceImpl)\n",
694*cc02d7e2SAndroid Build Coastguard Worker       "implclass", GetServerClassName(service));
695*cc02d7e2SAndroid Build Coastguard Worker   out->Print("{\n");
696*cc02d7e2SAndroid Build Coastguard Worker   out->Indent();
697*cc02d7e2SAndroid Build Coastguard Worker 
698*cc02d7e2SAndroid Build Coastguard Worker   out->Print("return grpc::ServerServiceDefinition.CreateBuilder()");
699*cc02d7e2SAndroid Build Coastguard Worker   out->Indent();
700*cc02d7e2SAndroid Build Coastguard Worker   out->Indent();
701*cc02d7e2SAndroid Build Coastguard Worker   for (int i = 0; i < service->method_count(); i++) {
702*cc02d7e2SAndroid Build Coastguard Worker     const MethodDescriptor* method = service->method(i);
703*cc02d7e2SAndroid Build Coastguard Worker     out->Print("\n.AddMethod($methodfield$, serviceImpl.$methodname$)",
704*cc02d7e2SAndroid Build Coastguard Worker                "methodfield", GetMethodFieldName(method), "methodname",
705*cc02d7e2SAndroid Build Coastguard Worker                method->name());
706*cc02d7e2SAndroid Build Coastguard Worker   }
707*cc02d7e2SAndroid Build Coastguard Worker   out->Print(".Build();\n");
708*cc02d7e2SAndroid Build Coastguard Worker   out->Outdent();
709*cc02d7e2SAndroid Build Coastguard Worker   out->Outdent();
710*cc02d7e2SAndroid Build Coastguard Worker 
711*cc02d7e2SAndroid Build Coastguard Worker   out->Outdent();
712*cc02d7e2SAndroid Build Coastguard Worker   out->Print("}\n");
713*cc02d7e2SAndroid Build Coastguard Worker   out->Print("\n");
714*cc02d7e2SAndroid Build Coastguard Worker }
715*cc02d7e2SAndroid Build Coastguard Worker 
GenerateBindServiceWithBinderMethod(Printer * out,const ServiceDescriptor * service)716*cc02d7e2SAndroid Build Coastguard Worker void GenerateBindServiceWithBinderMethod(Printer* out,
717*cc02d7e2SAndroid Build Coastguard Worker                                          const ServiceDescriptor* service) {
718*cc02d7e2SAndroid Build Coastguard Worker   out->Print(
719*cc02d7e2SAndroid Build Coastguard Worker       "/// <summary>Register service method with a service "
720*cc02d7e2SAndroid Build Coastguard Worker       "binder with or without implementation. Useful when customizing the "
721*cc02d7e2SAndroid Build Coastguard Worker       "service binding logic.\n"
722*cc02d7e2SAndroid Build Coastguard Worker       "/// Note: this method is part of an experimental API that can change or "
723*cc02d7e2SAndroid Build Coastguard Worker       "be "
724*cc02d7e2SAndroid Build Coastguard Worker       "removed without any prior notice.</summary>\n");
725*cc02d7e2SAndroid Build Coastguard Worker   out->Print(
726*cc02d7e2SAndroid Build Coastguard Worker       "/// <param name=\"serviceBinder\">Service methods will be bound by "
727*cc02d7e2SAndroid Build Coastguard Worker       "calling <c>AddMethod</c> on this object."
728*cc02d7e2SAndroid Build Coastguard Worker       "</param>\n");
729*cc02d7e2SAndroid Build Coastguard Worker   out->Print(
730*cc02d7e2SAndroid Build Coastguard Worker       "/// <param name=\"serviceImpl\">An object implementing the server-side"
731*cc02d7e2SAndroid Build Coastguard Worker       " handling logic.</param>\n");
732*cc02d7e2SAndroid Build Coastguard Worker   GenerateGeneratedCodeAttribute(out);
733*cc02d7e2SAndroid Build Coastguard Worker   out->Print(
734*cc02d7e2SAndroid Build Coastguard Worker       "public static void BindService(grpc::ServiceBinderBase serviceBinder, "
735*cc02d7e2SAndroid Build Coastguard Worker       "$implclass$ "
736*cc02d7e2SAndroid Build Coastguard Worker       "serviceImpl)\n",
737*cc02d7e2SAndroid Build Coastguard Worker       "implclass", GetServerClassName(service));
738*cc02d7e2SAndroid Build Coastguard Worker   out->Print("{\n");
739*cc02d7e2SAndroid Build Coastguard Worker   out->Indent();
740*cc02d7e2SAndroid Build Coastguard Worker 
741*cc02d7e2SAndroid Build Coastguard Worker   for (int i = 0; i < service->method_count(); i++) {
742*cc02d7e2SAndroid Build Coastguard Worker     const MethodDescriptor* method = service->method(i);
743*cc02d7e2SAndroid Build Coastguard Worker     out->Print(
744*cc02d7e2SAndroid Build Coastguard Worker         "serviceBinder.AddMethod($methodfield$, serviceImpl == null ? null : "
745*cc02d7e2SAndroid Build Coastguard Worker         "new $servermethodtype$<$inputtype$, $outputtype$>("
746*cc02d7e2SAndroid Build Coastguard Worker         "serviceImpl.$methodname$));\n",
747*cc02d7e2SAndroid Build Coastguard Worker         "methodfield", GetMethodFieldName(method), "servermethodtype",
748*cc02d7e2SAndroid Build Coastguard Worker         GetCSharpServerMethodType(method), "inputtype",
749*cc02d7e2SAndroid Build Coastguard Worker         GRPC_CUSTOM_CSHARP_GETCLASSNAME(method->input_type()), "outputtype",
750*cc02d7e2SAndroid Build Coastguard Worker         GRPC_CUSTOM_CSHARP_GETCLASSNAME(method->output_type()), "methodname",
751*cc02d7e2SAndroid Build Coastguard Worker         method->name());
752*cc02d7e2SAndroid Build Coastguard Worker   }
753*cc02d7e2SAndroid Build Coastguard Worker 
754*cc02d7e2SAndroid Build Coastguard Worker   out->Outdent();
755*cc02d7e2SAndroid Build Coastguard Worker   out->Print("}\n");
756*cc02d7e2SAndroid Build Coastguard Worker   out->Print("\n");
757*cc02d7e2SAndroid Build Coastguard Worker }
758*cc02d7e2SAndroid Build Coastguard Worker 
GenerateService(Printer * out,const ServiceDescriptor * service,bool generate_client,bool generate_server,bool internal_access)759*cc02d7e2SAndroid Build Coastguard Worker void GenerateService(Printer* out, const ServiceDescriptor* service,
760*cc02d7e2SAndroid Build Coastguard Worker                      bool generate_client, bool generate_server,
761*cc02d7e2SAndroid Build Coastguard Worker                      bool internal_access) {
762*cc02d7e2SAndroid Build Coastguard Worker   GenerateDocCommentBody(out, service);
763*cc02d7e2SAndroid Build Coastguard Worker 
764*cc02d7e2SAndroid Build Coastguard Worker   GenerateObsoleteAttribute(out, service->options().deprecated());
765*cc02d7e2SAndroid Build Coastguard Worker   out->Print("$access_level$ static partial class $classname$\n",
766*cc02d7e2SAndroid Build Coastguard Worker              "access_level", GetAccessLevel(internal_access), "classname",
767*cc02d7e2SAndroid Build Coastguard Worker              GetServiceClassName(service));
768*cc02d7e2SAndroid Build Coastguard Worker   out->Print("{\n");
769*cc02d7e2SAndroid Build Coastguard Worker   out->Indent();
770*cc02d7e2SAndroid Build Coastguard Worker   out->Print("static readonly string $servicenamefield$ = \"$servicename$\";\n",
771*cc02d7e2SAndroid Build Coastguard Worker              "servicenamefield", GetServiceNameFieldName(), "servicename",
772*cc02d7e2SAndroid Build Coastguard Worker              service->full_name());
773*cc02d7e2SAndroid Build Coastguard Worker   out->Print("\n");
774*cc02d7e2SAndroid Build Coastguard Worker 
775*cc02d7e2SAndroid Build Coastguard Worker   GenerateMarshallerFields(out, service);
776*cc02d7e2SAndroid Build Coastguard Worker   for (int i = 0; i < service->method_count(); i++) {
777*cc02d7e2SAndroid Build Coastguard Worker     GenerateStaticMethodField(out, service->method(i));
778*cc02d7e2SAndroid Build Coastguard Worker   }
779*cc02d7e2SAndroid Build Coastguard Worker   GenerateServiceDescriptorProperty(out, service);
780*cc02d7e2SAndroid Build Coastguard Worker 
781*cc02d7e2SAndroid Build Coastguard Worker   if (generate_server) {
782*cc02d7e2SAndroid Build Coastguard Worker     GenerateServerClass(out, service);
783*cc02d7e2SAndroid Build Coastguard Worker   }
784*cc02d7e2SAndroid Build Coastguard Worker   if (generate_client) {
785*cc02d7e2SAndroid Build Coastguard Worker     GenerateClientStub(out, service);
786*cc02d7e2SAndroid Build Coastguard Worker   }
787*cc02d7e2SAndroid Build Coastguard Worker   if (generate_server) {
788*cc02d7e2SAndroid Build Coastguard Worker     GenerateBindServiceMethod(out, service);
789*cc02d7e2SAndroid Build Coastguard Worker     GenerateBindServiceWithBinderMethod(out, service);
790*cc02d7e2SAndroid Build Coastguard Worker   }
791*cc02d7e2SAndroid Build Coastguard Worker 
792*cc02d7e2SAndroid Build Coastguard Worker   out->Outdent();
793*cc02d7e2SAndroid Build Coastguard Worker   out->Print("}\n");
794*cc02d7e2SAndroid Build Coastguard Worker }
795*cc02d7e2SAndroid Build Coastguard Worker 
796*cc02d7e2SAndroid Build Coastguard Worker }  // anonymous namespace
797*cc02d7e2SAndroid Build Coastguard Worker 
GetServices(const FileDescriptor * file,bool generate_client,bool generate_server,bool internal_access)798*cc02d7e2SAndroid Build Coastguard Worker std::string GetServices(const FileDescriptor* file, bool generate_client,
799*cc02d7e2SAndroid Build Coastguard Worker                         bool generate_server, bool internal_access) {
800*cc02d7e2SAndroid Build Coastguard Worker   std::string output;
801*cc02d7e2SAndroid Build Coastguard Worker   {
802*cc02d7e2SAndroid Build Coastguard Worker     // Scope the output stream so it closes and finalizes output to the string.
803*cc02d7e2SAndroid Build Coastguard Worker 
804*cc02d7e2SAndroid Build Coastguard Worker     StringOutputStream output_stream(&output);
805*cc02d7e2SAndroid Build Coastguard Worker     Printer out(&output_stream, '$');
806*cc02d7e2SAndroid Build Coastguard Worker 
807*cc02d7e2SAndroid Build Coastguard Worker     // Don't write out any output if there no services, to avoid empty service
808*cc02d7e2SAndroid Build Coastguard Worker     // files being generated for proto files that don't declare any.
809*cc02d7e2SAndroid Build Coastguard Worker     if (file->service_count() == 0) {
810*cc02d7e2SAndroid Build Coastguard Worker       return output;
811*cc02d7e2SAndroid Build Coastguard Worker     }
812*cc02d7e2SAndroid Build Coastguard Worker 
813*cc02d7e2SAndroid Build Coastguard Worker     // Write out a file header.
814*cc02d7e2SAndroid Build Coastguard Worker     out.Print("// <auto-generated>\n");
815*cc02d7e2SAndroid Build Coastguard Worker     out.Print(
816*cc02d7e2SAndroid Build Coastguard Worker         "//     Generated by the protocol buffer compiler.  DO NOT EDIT!\n");
817*cc02d7e2SAndroid Build Coastguard Worker     out.Print("//     source: $filename$\n", "filename", file->name());
818*cc02d7e2SAndroid Build Coastguard Worker     out.Print("// </auto-generated>\n");
819*cc02d7e2SAndroid Build Coastguard Worker 
820*cc02d7e2SAndroid Build Coastguard Worker     // use C++ style as there are no file-level XML comments in .NET
821*cc02d7e2SAndroid Build Coastguard Worker     std::string leading_comments = GetCsharpComments(file, true);
822*cc02d7e2SAndroid Build Coastguard Worker     if (!leading_comments.empty()) {
823*cc02d7e2SAndroid Build Coastguard Worker       out.Print("// Original file comments:\n");
824*cc02d7e2SAndroid Build Coastguard Worker       out.PrintRaw(leading_comments.c_str());
825*cc02d7e2SAndroid Build Coastguard Worker     }
826*cc02d7e2SAndroid Build Coastguard Worker 
827*cc02d7e2SAndroid Build Coastguard Worker     out.Print("#pragma warning disable 0414, 1591, 8981, 0612\n");
828*cc02d7e2SAndroid Build Coastguard Worker 
829*cc02d7e2SAndroid Build Coastguard Worker     out.Print("#region Designer generated code\n");
830*cc02d7e2SAndroid Build Coastguard Worker     out.Print("\n");
831*cc02d7e2SAndroid Build Coastguard Worker     out.Print("using grpc = global::Grpc.Core;\n");
832*cc02d7e2SAndroid Build Coastguard Worker     out.Print("\n");
833*cc02d7e2SAndroid Build Coastguard Worker 
834*cc02d7e2SAndroid Build Coastguard Worker     std::string file_namespace = GRPC_CUSTOM_CSHARP_GETFILENAMESPACE(file);
835*cc02d7e2SAndroid Build Coastguard Worker     if (file_namespace != "") {
836*cc02d7e2SAndroid Build Coastguard Worker       out.Print("namespace $namespace$ {\n", "namespace", file_namespace);
837*cc02d7e2SAndroid Build Coastguard Worker       out.Indent();
838*cc02d7e2SAndroid Build Coastguard Worker     }
839*cc02d7e2SAndroid Build Coastguard Worker     for (int i = 0; i < file->service_count(); i++) {
840*cc02d7e2SAndroid Build Coastguard Worker       GenerateService(&out, file->service(i), generate_client, generate_server,
841*cc02d7e2SAndroid Build Coastguard Worker                       internal_access);
842*cc02d7e2SAndroid Build Coastguard Worker     }
843*cc02d7e2SAndroid Build Coastguard Worker     if (file_namespace != "") {
844*cc02d7e2SAndroid Build Coastguard Worker       out.Outdent();
845*cc02d7e2SAndroid Build Coastguard Worker       out.Print("}\n");
846*cc02d7e2SAndroid Build Coastguard Worker     }
847*cc02d7e2SAndroid Build Coastguard Worker     out.Print("#endregion\n");
848*cc02d7e2SAndroid Build Coastguard Worker   }
849*cc02d7e2SAndroid Build Coastguard Worker   return output;
850*cc02d7e2SAndroid Build Coastguard Worker }
851*cc02d7e2SAndroid Build Coastguard Worker 
852*cc02d7e2SAndroid Build Coastguard Worker }  // namespace grpc_csharp_generator
853