Protocol Buffers - Google's data interchange format (grpc依赖) https://developers.google.com/protocol-buffers/
 
 
 
 
 
 

138 lines
6.2 KiB

using System;
using System.Collections.Generic;
using System.Text;
using Google.ProtocolBuffers.Descriptors;
namespace Google.ProtocolBuffers.ProtoGen {
internal class ServiceGenerator : SourceGeneratorBase<ServiceDescriptor>, ISourceGenerator {
private enum RequestOrResponse {
Request,
Response
}
internal ServiceGenerator(ServiceDescriptor descriptor)
: base(descriptor) {
}
public void Generate(TextGenerator writer) {
writer.WriteLine("{0} abstract class {1} : pb::IService {{", ClassAccessLevel, Descriptor.Name);
writer.Indent();
foreach (MethodDescriptor method in Descriptor.Methods) {
writer.WriteLine("{0} abstract void {1}(", ClassAccessLevel, Helpers.UnderscoresToPascalCase(method.Name));
writer.WriteLine(" pb::IRpcController controller,");
writer.WriteLine(" {0} request,", DescriptorUtil.GetClassName(method.InputType));
writer.WriteLine(" global::System.Action<{0}> done);", DescriptorUtil.GetClassName(method.OutputType));
}
// Generate Descriptor and DescriptorForType.
writer.WriteLine();
writer.WriteLine("{0} static pbd::ServiceDescriptor Descriptor {{", ClassAccessLevel);
writer.WriteLine(" get {{ return {0}.Descriptor.Services[{1}]; }}",
DescriptorUtil.GetUmbrellaClassName(Descriptor.File), Descriptor.Index);
writer.WriteLine("}");
writer.WriteLine("{0} pbd::ServiceDescriptor DescriptorForType {{", ClassAccessLevel);
writer.WriteLine(" get { return Descriptor; }");
writer.WriteLine("}");
GenerateCallMethod(writer);
GenerateGetPrototype(RequestOrResponse.Request, writer);
GenerateGetPrototype(RequestOrResponse.Response, writer);
GenerateStub(writer);
writer.Outdent();
writer.WriteLine("}");
}
private void GenerateCallMethod(TextGenerator writer) {
writer.WriteLine();
writer.WriteLine("public void CallMethod(", ClassAccessLevel);
writer.WriteLine(" pbd::MethodDescriptor method,");
writer.WriteLine(" pb::IRpcController controller,");
writer.WriteLine(" pb::IMessage request,");
writer.WriteLine(" global::System.Action<pb::IMessage> done) {");
writer.Indent();
writer.WriteLine("if (method.Service != Descriptor) {");
writer.WriteLine(" throw new global::System.ArgumentException(");
writer.WriteLine(" \"Service.CallMethod() given method descriptor for wrong service type.\");");
writer.WriteLine("}");
writer.WriteLine("switch(method.Index) {");
writer.Indent();
foreach (MethodDescriptor method in Descriptor.Methods) {
writer.WriteLine("case {0}:", method.Index);
writer.WriteLine(" this.{0}(controller, ({0}) request,",
Helpers.UnderscoresToPascalCase(method.Name), DescriptorUtil.GetClassName(method.InputType));
writer.WriteLine(" pb::RpcUtil.SpecializeCallback<{0}>(", DescriptorUtil.GetClassName(method.OutputType));
writer.WriteLine(" done));");
writer.WriteLine(" return;");
}
writer.WriteLine("default:");
writer.WriteLine(" throw new global::System.InvalidOperationException(\"Can't get here.\");");
writer.Outdent();
writer.WriteLine("}");
writer.Outdent();
writer.WriteLine("}");
writer.WriteLine();
}
private void GenerateGetPrototype(RequestOrResponse which, TextGenerator writer) {
writer.WriteLine("public pb::IMessage Get{0}Prototype(pbd::MethodDescriptor method) {{", which);
writer.Indent();
writer.WriteLine("if (method.Service != Descriptor) {");
writer.WriteLine(" throw new global::System.ArgumentException(");
writer.WriteLine(" \"Service.Get{0}Prototype() given method descriptor for wrong service type.\");", which);
writer.WriteLine("}");
writer.WriteLine("switch(method.Index) {");
writer.Indent();
foreach (MethodDescriptor method in Descriptor.Methods) {
writer.WriteLine("case {0}:", method.Index);
writer.WriteLine(" return {0}.DefaultInstance;",
DescriptorUtil.GetClassName(which == RequestOrResponse.Request ? method.InputType : method.OutputType));
}
writer.WriteLine("default:");
writer.WriteLine(" throw new global::System.InvalidOperationException(\"Can't get here.\");");
writer.Outdent();
writer.WriteLine("}");
writer.Outdent();
writer.WriteLine("}");
writer.WriteLine();
}
private void GenerateStub(TextGenerator writer) {
writer.WriteLine("public static Stub CreateStub(pb::IRpcChannel channel) {");
writer.WriteLine(" return new Stub(channel);");
writer.WriteLine("}");
writer.WriteLine();
writer.WriteLine("{0} class Stub : {1} {{", ClassAccessLevel, DescriptorUtil.GetClassName(Descriptor));
writer.Indent();
writer.WriteLine("internal Stub(pb::IRpcChannel channel) {");
writer.WriteLine(" this.channel = channel;");
writer.WriteLine("}");
writer.WriteLine();
writer.WriteLine("private readonly pb::IRpcChannel channel;");
writer.WriteLine();
writer.WriteLine("public pb::IRpcChannel Channel {");
writer.WriteLine(" get { return channel; }");
writer.WriteLine("}");
foreach (MethodDescriptor method in Descriptor.Methods) {
writer.WriteLine();
writer.WriteLine("public override void {0}(", Helpers.UnderscoresToPascalCase(method.Name));
writer.WriteLine(" pb::IRpcController controller,");
writer.WriteLine(" {0} request,", DescriptorUtil.GetClassName(method.InputType));
writer.WriteLine(" global::System.Action<{0}> done) {{", DescriptorUtil.GetClassName(method.OutputType));
writer.Indent();
writer.WriteLine("channel.CallMethod(Descriptor.Methods[{0}],", method.Index);
writer.WriteLine(" controller, request, {0}.DefaultInstance,", DescriptorUtil.GetClassName(method.OutputType));
writer.WriteLine(" pb::RpcUtil.GeneralizeCallback<{0}, {0}.Builder>(done, {0}.DefaultInstance));",
DescriptorUtil.GetClassName(method.OutputType));
writer.Outdent();
writer.WriteLine("}");
}
writer.Outdent();
writer.WriteLine("}");
}
}
}