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


grpc
Author(s):
autogenerated on Thu Mar 13 2025 02:59:01