| Index: third_party/grpc/src/compiler/csharp_generator.cc
|
| diff --git a/third_party/grpc/src/compiler/csharp_generator.cc b/third_party/grpc/src/compiler/csharp_generator.cc
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..f6079bdc05abfd6af67faf117598b451324f46ab
|
| --- /dev/null
|
| +++ b/third_party/grpc/src/compiler/csharp_generator.cc
|
| @@ -0,0 +1,539 @@
|
| +/*
|
| + *
|
| + * Copyright 2015-2016, Google Inc.
|
| + * All rights reserved.
|
| + *
|
| + * Redistribution and use in source and binary forms, with or without
|
| + * modification, are permitted provided that the following conditions are
|
| + * met:
|
| + *
|
| + * * Redistributions of source code must retain the above copyright
|
| + * notice, this list of conditions and the following disclaimer.
|
| + * * Redistributions in binary form must reproduce the above
|
| + * copyright notice, this list of conditions and the following disclaimer
|
| + * in the documentation and/or other materials provided with the
|
| + * distribution.
|
| + * * Neither the name of Google Inc. nor the names of its
|
| + * contributors may be used to endorse or promote products derived from
|
| + * this software without specific prior written permission.
|
| + *
|
| + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
| + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
| + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
| + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
| + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
| + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
| + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
| + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
| + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
| + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
| + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
| + *
|
| + */
|
| +
|
| +#include <cctype>
|
| +#include <map>
|
| +#include <sstream>
|
| +#include <vector>
|
| +
|
| +#include "src/compiler/csharp_generator.h"
|
| +#include "src/compiler/config.h"
|
| +#include "src/compiler/csharp_generator_helpers.h"
|
| +#include "src/compiler/csharp_generator.h"
|
| +
|
| +
|
| +using google::protobuf::compiler::csharp::GetFileNamespace;
|
| +using google::protobuf::compiler::csharp::GetClassName;
|
| +using google::protobuf::compiler::csharp::GetReflectionClassName;
|
| +using grpc::protobuf::FileDescriptor;
|
| +using grpc::protobuf::Descriptor;
|
| +using grpc::protobuf::ServiceDescriptor;
|
| +using grpc::protobuf::MethodDescriptor;
|
| +using grpc::protobuf::io::Printer;
|
| +using grpc::protobuf::io::StringOutputStream;
|
| +using grpc_generator::MethodType;
|
| +using grpc_generator::GetMethodType;
|
| +using grpc_generator::METHODTYPE_NO_STREAMING;
|
| +using grpc_generator::METHODTYPE_CLIENT_STREAMING;
|
| +using grpc_generator::METHODTYPE_SERVER_STREAMING;
|
| +using grpc_generator::METHODTYPE_BIDI_STREAMING;
|
| +using grpc_generator::StringReplace;
|
| +using std::map;
|
| +using std::vector;
|
| +
|
| +
|
| +namespace grpc_csharp_generator {
|
| +namespace {
|
| +
|
| +std::string GetServiceClassName(const ServiceDescriptor* service) {
|
| + return service->name();
|
| +}
|
| +
|
| +std::string GetClientInterfaceName(const ServiceDescriptor* service) {
|
| + return "I" + service->name() + "Client";
|
| +}
|
| +
|
| +std::string GetClientClassName(const ServiceDescriptor* service) {
|
| + return service->name() + "Client";
|
| +}
|
| +
|
| +std::string GetServerInterfaceName(const ServiceDescriptor* service) {
|
| + return "I" + service->name();
|
| +}
|
| +
|
| +std::string GetCSharpMethodType(MethodType method_type) {
|
| + switch (method_type) {
|
| + case METHODTYPE_NO_STREAMING:
|
| + return "MethodType.Unary";
|
| + case METHODTYPE_CLIENT_STREAMING:
|
| + return "MethodType.ClientStreaming";
|
| + case METHODTYPE_SERVER_STREAMING:
|
| + return "MethodType.ServerStreaming";
|
| + case METHODTYPE_BIDI_STREAMING:
|
| + return "MethodType.DuplexStreaming";
|
| + }
|
| + GOOGLE_LOG(FATAL)<< "Can't get here.";
|
| + return "";
|
| +}
|
| +
|
| +std::string GetServiceNameFieldName() {
|
| + return "__ServiceName";
|
| +}
|
| +
|
| +std::string GetMarshallerFieldName(const Descriptor *message) {
|
| + return "__Marshaller_" + message->name();
|
| +}
|
| +
|
| +std::string GetMethodFieldName(const MethodDescriptor *method) {
|
| + return "__Method_" + method->name();
|
| +}
|
| +
|
| +std::string GetMethodRequestParamMaybe(const MethodDescriptor *method) {
|
| + if (method->client_streaming()) {
|
| + return "";
|
| + }
|
| + return GetClassName(method->input_type()) + " request, ";
|
| +}
|
| +
|
| +std::string GetMethodReturnTypeClient(const MethodDescriptor *method) {
|
| + switch (GetMethodType(method)) {
|
| + case METHODTYPE_NO_STREAMING:
|
| + return "AsyncUnaryCall<" + GetClassName(method->output_type()) + ">";
|
| + case METHODTYPE_CLIENT_STREAMING:
|
| + return "AsyncClientStreamingCall<" + GetClassName(method->input_type())
|
| + + ", " + GetClassName(method->output_type()) + ">";
|
| + case METHODTYPE_SERVER_STREAMING:
|
| + return "AsyncServerStreamingCall<" + GetClassName(method->output_type())
|
| + + ">";
|
| + case METHODTYPE_BIDI_STREAMING:
|
| + return "AsyncDuplexStreamingCall<" + GetClassName(method->input_type())
|
| + + ", " + GetClassName(method->output_type()) + ">";
|
| + }
|
| + GOOGLE_LOG(FATAL)<< "Can't get here.";
|
| + return "";
|
| +}
|
| +
|
| +std::string GetMethodRequestParamServer(const MethodDescriptor *method) {
|
| + switch (GetMethodType(method)) {
|
| + case METHODTYPE_NO_STREAMING:
|
| + case METHODTYPE_SERVER_STREAMING:
|
| + return GetClassName(method->input_type()) + " request";
|
| + case METHODTYPE_CLIENT_STREAMING:
|
| + case METHODTYPE_BIDI_STREAMING:
|
| + return "IAsyncStreamReader<" + GetClassName(method->input_type())
|
| + + "> requestStream";
|
| + }
|
| + GOOGLE_LOG(FATAL)<< "Can't get here.";
|
| + return "";
|
| +}
|
| +
|
| +std::string GetMethodReturnTypeServer(const MethodDescriptor *method) {
|
| + switch (GetMethodType(method)) {
|
| + case METHODTYPE_NO_STREAMING:
|
| + case METHODTYPE_CLIENT_STREAMING:
|
| + return "Task<" + GetClassName(method->output_type()) + ">";
|
| + case METHODTYPE_SERVER_STREAMING:
|
| + case METHODTYPE_BIDI_STREAMING:
|
| + return "Task";
|
| + }
|
| + GOOGLE_LOG(FATAL)<< "Can't get here.";
|
| + return "";
|
| +}
|
| +
|
| +std::string GetMethodResponseStreamMaybe(const MethodDescriptor *method) {
|
| + switch (GetMethodType(method)) {
|
| + case METHODTYPE_NO_STREAMING:
|
| + case METHODTYPE_CLIENT_STREAMING:
|
| + return "";
|
| + case METHODTYPE_SERVER_STREAMING:
|
| + case METHODTYPE_BIDI_STREAMING:
|
| + return ", IServerStreamWriter<" + GetClassName(method->output_type())
|
| + + "> responseStream";
|
| + }
|
| + GOOGLE_LOG(FATAL)<< "Can't get here.";
|
| + return "";
|
| +}
|
| +
|
| +// Gets vector of all messages used as input or output types.
|
| +std::vector<const Descriptor*> GetUsedMessages(
|
| + const ServiceDescriptor *service) {
|
| + std::set<const Descriptor*> descriptor_set;
|
| + std::vector<const Descriptor*> result; // vector is to maintain stable ordering
|
| + for (int i = 0; i < service->method_count(); i++) {
|
| + const MethodDescriptor *method = service->method(i);
|
| + if (descriptor_set.find(method->input_type()) == descriptor_set.end()) {
|
| + descriptor_set.insert(method->input_type());
|
| + result.push_back(method->input_type());
|
| + }
|
| + if (descriptor_set.find(method->output_type()) == descriptor_set.end()) {
|
| + descriptor_set.insert(method->output_type());
|
| + result.push_back(method->output_type());
|
| + }
|
| + }
|
| + return result;
|
| +}
|
| +
|
| +void GenerateMarshallerFields(Printer* out, const ServiceDescriptor *service) {
|
| + std::vector<const Descriptor*> used_messages = GetUsedMessages(service);
|
| + for (size_t i = 0; i < used_messages.size(); i++) {
|
| + const Descriptor *message = used_messages[i];
|
| + out->Print(
|
| + "static readonly Marshaller<$type$> $fieldname$ = Marshallers.Create((arg) => global::Google.Protobuf.MessageExtensions.ToByteArray(arg), $type$.Parser.ParseFrom);\n",
|
| + "fieldname", GetMarshallerFieldName(message), "type",
|
| + GetClassName(message));
|
| + }
|
| + out->Print("\n");
|
| +}
|
| +
|
| +void GenerateStaticMethodField(Printer* out, const MethodDescriptor *method) {
|
| + out->Print(
|
| + "static readonly Method<$request$, $response$> $fieldname$ = new Method<$request$, $response$>(\n",
|
| + "fieldname", GetMethodFieldName(method), "request",
|
| + GetClassName(method->input_type()), "response",
|
| + GetClassName(method->output_type()));
|
| + out->Indent();
|
| + out->Indent();
|
| + out->Print("$methodtype$,\n", "methodtype",
|
| + GetCSharpMethodType(GetMethodType(method)));
|
| + out->Print("$servicenamefield$,\n", "servicenamefield",
|
| + GetServiceNameFieldName());
|
| + out->Print("\"$methodname$\",\n", "methodname", method->name());
|
| + out->Print("$requestmarshaller$,\n", "requestmarshaller",
|
| + GetMarshallerFieldName(method->input_type()));
|
| + out->Print("$responsemarshaller$);\n", "responsemarshaller",
|
| + GetMarshallerFieldName(method->output_type()));
|
| + out->Print("\n");
|
| + out->Outdent();
|
| + out->Outdent();
|
| +}
|
| +
|
| +void GenerateServiceDescriptorProperty(Printer* out, const ServiceDescriptor *service) {
|
| + std::ostringstream index;
|
| + index << service->index();
|
| + out->Print("// service descriptor\n");
|
| + out->Print("public static global::Google.Protobuf.Reflection.ServiceDescriptor Descriptor\n");
|
| + out->Print("{\n");
|
| + out->Print(" get { return $umbrella$.Descriptor.Services[$index$]; }\n",
|
| + "umbrella", GetReflectionClassName(service->file()), "index",
|
| + index.str());
|
| + out->Print("}\n");
|
| + out->Print("\n");
|
| +}
|
| +
|
| +void GenerateClientInterface(Printer* out, const ServiceDescriptor *service) {
|
| + out->Print("// client interface\n");
|
| + out->Print("public interface $name$\n", "name",
|
| + GetClientInterfaceName(service));
|
| + out->Print("{\n");
|
| + out->Indent();
|
| + for (int i = 0; i < service->method_count(); i++) {
|
| + const MethodDescriptor *method = service->method(i);
|
| + MethodType method_type = GetMethodType(method);
|
| +
|
| + if (method_type == METHODTYPE_NO_STREAMING) {
|
| + // unary calls have an extra synchronous stub method
|
| + out->Print(
|
| + "$response$ $methodname$($request$ request, Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken));\n",
|
| + "methodname", method->name(), "request",
|
| + GetClassName(method->input_type()), "response",
|
| + GetClassName(method->output_type()));
|
| +
|
| + // overload taking CallOptions as a param
|
| + out->Print(
|
| + "$response$ $methodname$($request$ request, CallOptions options);\n",
|
| + "methodname", method->name(), "request",
|
| + GetClassName(method->input_type()), "response",
|
| + GetClassName(method->output_type()));
|
| + }
|
| +
|
| + std::string method_name = method->name();
|
| + if (method_type == METHODTYPE_NO_STREAMING) {
|
| + method_name += "Async"; // prevent name clash with synchronous method.
|
| + }
|
| + out->Print(
|
| + "$returntype$ $methodname$($request_maybe$Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken));\n",
|
| + "methodname", method_name, "request_maybe",
|
| + GetMethodRequestParamMaybe(method), "returntype",
|
| + GetMethodReturnTypeClient(method));
|
| +
|
| + // overload taking CallOptions as a param
|
| + out->Print(
|
| + "$returntype$ $methodname$($request_maybe$CallOptions options);\n",
|
| + "methodname", method_name, "request_maybe",
|
| + GetMethodRequestParamMaybe(method), "returntype",
|
| + GetMethodReturnTypeClient(method));
|
| + }
|
| + out->Outdent();
|
| + out->Print("}\n");
|
| + out->Print("\n");
|
| +}
|
| +
|
| +void GenerateServerInterface(Printer* out, const ServiceDescriptor *service) {
|
| + out->Print("// server-side interface\n");
|
| + out->Print("public interface $name$\n", "name",
|
| + GetServerInterfaceName(service));
|
| + out->Print("{\n");
|
| + out->Indent();
|
| + for (int i = 0; i < service->method_count(); i++) {
|
| + const MethodDescriptor *method = service->method(i);
|
| + out->Print(
|
| + "$returntype$ $methodname$($request$$response_stream_maybe$, "
|
| + "ServerCallContext context);\n",
|
| + "methodname", method->name(), "returntype",
|
| + GetMethodReturnTypeServer(method), "request",
|
| + GetMethodRequestParamServer(method), "response_stream_maybe",
|
| + GetMethodResponseStreamMaybe(method));
|
| + }
|
| + out->Outdent();
|
| + out->Print("}\n");
|
| + out->Print("\n");
|
| +}
|
| +
|
| +void GenerateClientStub(Printer* out, const ServiceDescriptor *service) {
|
| + out->Print("// client stub\n");
|
| + out->Print(
|
| + "public class $name$ : ClientBase, $interface$\n",
|
| + "name", GetClientClassName(service), "interface",
|
| + GetClientInterfaceName(service));
|
| + out->Print("{\n");
|
| + out->Indent();
|
| +
|
| + // constructors
|
| + out->Print(
|
| + "public $name$(Channel channel) : base(channel)\n",
|
| + "name", GetClientClassName(service));
|
| + out->Print("{\n");
|
| + out->Print("}\n");
|
| +
|
| + for (int i = 0; i < service->method_count(); i++) {
|
| + const MethodDescriptor *method = service->method(i);
|
| + MethodType method_type = GetMethodType(method);
|
| +
|
| + if (method_type == METHODTYPE_NO_STREAMING) {
|
| + // unary calls have an extra synchronous stub method
|
| + out->Print(
|
| + "public $response$ $methodname$($request$ request, Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken))\n",
|
| + "methodname", method->name(), "request",
|
| + GetClassName(method->input_type()), "response",
|
| + GetClassName(method->output_type()));
|
| + out->Print("{\n");
|
| + out->Indent();
|
| + out->Print("var call = CreateCall($methodfield$, new CallOptions(headers, deadline, cancellationToken));\n",
|
| + "methodfield", GetMethodFieldName(method));
|
| + out->Print("return Calls.BlockingUnaryCall(call, request);\n");
|
| + out->Outdent();
|
| + out->Print("}\n");
|
| +
|
| + // overload taking CallOptions as a param
|
| + out->Print(
|
| + "public $response$ $methodname$($request$ request, CallOptions options)\n",
|
| + "methodname", method->name(), "request",
|
| + GetClassName(method->input_type()), "response",
|
| + GetClassName(method->output_type()));
|
| + out->Print("{\n");
|
| + out->Indent();
|
| + out->Print("var call = CreateCall($methodfield$, options);\n",
|
| + "methodfield", GetMethodFieldName(method));
|
| + out->Print("return Calls.BlockingUnaryCall(call, request);\n");
|
| + out->Outdent();
|
| + out->Print("}\n");
|
| + }
|
| +
|
| + std::string method_name = method->name();
|
| + if (method_type == METHODTYPE_NO_STREAMING) {
|
| + method_name += "Async"; // prevent name clash with synchronous method.
|
| + }
|
| + out->Print(
|
| + "public $returntype$ $methodname$($request_maybe$Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken))\n",
|
| + "methodname", method_name, "request_maybe",
|
| + GetMethodRequestParamMaybe(method), "returntype",
|
| + GetMethodReturnTypeClient(method));
|
| + out->Print("{\n");
|
| + out->Indent();
|
| + out->Print("var call = CreateCall($methodfield$, new CallOptions(headers, deadline, cancellationToken));\n",
|
| + "methodfield", GetMethodFieldName(method));
|
| + switch (GetMethodType(method)) {
|
| + case METHODTYPE_NO_STREAMING:
|
| + out->Print("return Calls.AsyncUnaryCall(call, request);\n");
|
| + break;
|
| + case METHODTYPE_CLIENT_STREAMING:
|
| + out->Print("return Calls.AsyncClientStreamingCall(call);\n");
|
| + break;
|
| + case METHODTYPE_SERVER_STREAMING:
|
| + out->Print(
|
| + "return Calls.AsyncServerStreamingCall(call, request);\n");
|
| + break;
|
| + case METHODTYPE_BIDI_STREAMING:
|
| + out->Print("return Calls.AsyncDuplexStreamingCall(call);\n");
|
| + break;
|
| + default:
|
| + GOOGLE_LOG(FATAL)<< "Can't get here.";
|
| + }
|
| + out->Outdent();
|
| + out->Print("}\n");
|
| +
|
| + // overload taking CallOptions as a param
|
| + out->Print(
|
| + "public $returntype$ $methodname$($request_maybe$CallOptions options)\n",
|
| + "methodname", method_name, "request_maybe",
|
| + GetMethodRequestParamMaybe(method), "returntype",
|
| + GetMethodReturnTypeClient(method));
|
| + out->Print("{\n");
|
| + out->Indent();
|
| + out->Print("var call = CreateCall($methodfield$, options);\n",
|
| + "methodfield", GetMethodFieldName(method));
|
| + switch (GetMethodType(method)) {
|
| + case METHODTYPE_NO_STREAMING:
|
| + out->Print("return Calls.AsyncUnaryCall(call, request);\n");
|
| + break;
|
| + case METHODTYPE_CLIENT_STREAMING:
|
| + out->Print("return Calls.AsyncClientStreamingCall(call);\n");
|
| + break;
|
| + case METHODTYPE_SERVER_STREAMING:
|
| + out->Print(
|
| + "return Calls.AsyncServerStreamingCall(call, request);\n");
|
| + break;
|
| + case METHODTYPE_BIDI_STREAMING:
|
| + out->Print("return Calls.AsyncDuplexStreamingCall(call);\n");
|
| + break;
|
| + default:
|
| + GOOGLE_LOG(FATAL)<< "Can't get here.";
|
| + }
|
| + out->Outdent();
|
| + out->Print("}\n");
|
| + }
|
| + out->Outdent();
|
| + out->Print("}\n");
|
| + out->Print("\n");
|
| +}
|
| +
|
| +void GenerateBindServiceMethod(Printer* out, const ServiceDescriptor *service) {
|
| + out->Print(
|
| + "// creates service definition that can be registered with a server\n");
|
| + out->Print(
|
| + "public static ServerServiceDefinition BindService($interface$ serviceImpl)\n",
|
| + "interface", GetServerInterfaceName(service));
|
| + out->Print("{\n");
|
| + out->Indent();
|
| +
|
| + out->Print(
|
| + "return ServerServiceDefinition.CreateBuilder($servicenamefield$)\n",
|
| + "servicenamefield", GetServiceNameFieldName());
|
| + out->Indent();
|
| + out->Indent();
|
| + for (int i = 0; i < service->method_count(); i++) {
|
| + const MethodDescriptor *method = service->method(i);
|
| + out->Print(".AddMethod($methodfield$, serviceImpl.$methodname$)",
|
| + "methodfield", GetMethodFieldName(method), "methodname",
|
| + method->name());
|
| + if (i == service->method_count() - 1) {
|
| + out->Print(".Build();");
|
| + }
|
| + out->Print("\n");
|
| + }
|
| + out->Outdent();
|
| + out->Outdent();
|
| +
|
| + out->Outdent();
|
| + out->Print("}\n");
|
| + out->Print("\n");
|
| +}
|
| +
|
| +void GenerateNewStubMethods(Printer* out, const ServiceDescriptor *service) {
|
| + out->Print("// creates a new client\n");
|
| + out->Print("public static $classname$ NewClient(Channel channel)\n",
|
| + "classname", GetClientClassName(service));
|
| + out->Print("{\n");
|
| + out->Indent();
|
| + out->Print("return new $classname$(channel);\n", "classname",
|
| + GetClientClassName(service));
|
| + out->Outdent();
|
| + out->Print("}\n");
|
| + out->Print("\n");
|
| +}
|
| +
|
| +void GenerateService(Printer* out, const ServiceDescriptor *service) {
|
| + out->Print("public static class $classname$\n", "classname",
|
| + GetServiceClassName(service));
|
| + out->Print("{\n");
|
| + out->Indent();
|
| + out->Print("static readonly string $servicenamefield$ = \"$servicename$\";\n",
|
| + "servicenamefield", GetServiceNameFieldName(), "servicename",
|
| + service->full_name());
|
| + out->Print("\n");
|
| +
|
| + GenerateMarshallerFields(out, service);
|
| + for (int i = 0; i < service->method_count(); i++) {
|
| + GenerateStaticMethodField(out, service->method(i));
|
| + }
|
| + GenerateServiceDescriptorProperty(out, service);
|
| + GenerateClientInterface(out, service);
|
| + GenerateServerInterface(out, service);
|
| + GenerateClientStub(out, service);
|
| + GenerateBindServiceMethod(out, service);
|
| + GenerateNewStubMethods(out, service);
|
| +
|
| + out->Outdent();
|
| + out->Print("}\n");
|
| +}
|
| +
|
| +} // anonymous namespace
|
| +
|
| +grpc::string GetServices(const FileDescriptor *file) {
|
| + grpc::string output;
|
| + {
|
| + // Scope the output stream so it closes and finalizes output to the string.
|
| +
|
| + StringOutputStream output_stream(&output);
|
| + Printer out(&output_stream, '$');
|
| +
|
| + // Don't write out any output if there no services, to avoid empty service
|
| + // files being generated for proto files that don't declare any.
|
| + if (file->service_count() == 0) {
|
| + return output;
|
| + }
|
| +
|
| + // Write out a file header.
|
| + out.Print("// Generated by the protocol buffer compiler. DO NOT EDIT!\n");
|
| + out.Print("// source: $filename$\n", "filename", file->name());
|
| + out.Print("#region Designer generated code\n");
|
| + out.Print("\n");
|
| + out.Print("using System;\n");
|
| + out.Print("using System.Threading;\n");
|
| + out.Print("using System.Threading.Tasks;\n");
|
| + out.Print("using Grpc.Core;\n");
|
| + out.Print("\n");
|
| +
|
| + out.Print("namespace $namespace$ {\n", "namespace", GetFileNamespace(file));
|
| + out.Indent();
|
| + for (int i = 0; i < file->service_count(); i++) {
|
| + GenerateService(&out, file->service(i));
|
| + }
|
| + out.Outdent();
|
| + out.Print("}\n");
|
| + out.Print("#endregion\n");
|
| + }
|
| + return output;
|
| +}
|
| +
|
| +} // namespace grpc_csharp_generator
|
|
|