parent
82bb0f1ef9
commit
68d831e3a4
15 changed files with 2960 additions and 712 deletions
@ -0,0 +1,34 @@ |
||||
// Additional options required for C# generation. File from copyright |
||||
// line onwards is as per original distribution. |
||||
import "google/protobuf/csharp_options.proto"; |
||||
option (google.protobuf.csharp_file_options).namespace = "Google.ProtocolBuffers.TestProtos"; |
||||
option (google.protobuf.csharp_file_options).umbrella_classname = "UnitTestRpcInterop"; |
||||
|
||||
option (google.protobuf.csharp_file_options).service_generator_type = IRPCDISPATCH; |
||||
|
||||
option optimize_for = SPEED; |
||||
|
||||
message SearchRequest { |
||||
repeated string Criteria = 1; |
||||
} |
||||
|
||||
message SearchResponse { |
||||
message ResultItem { |
||||
required string url = 1; |
||||
optional string name = 2; |
||||
} |
||||
|
||||
repeated ResultItem results = 1; |
||||
} |
||||
|
||||
message RefineSearchRequest { |
||||
repeated string Criteria = 1; |
||||
required SearchResponse previous_results = 2; |
||||
} |
||||
|
||||
service SearchService { |
||||
option (google.protobuf.csharp_service_options).interface_id = "{A65F0925-FD11-4f94-B166-89AC4F027205}"; |
||||
rpc Search (SearchRequest) returns (SearchResponse) { option (google.protobuf.csharp_method_options).dispatch_id = 5; }; |
||||
|
||||
rpc RefineSearch (RefineSearchRequest) returns (SearchResponse); |
||||
} |
@ -1,73 +1,103 @@ |
||||
// Extra options for C# generator |
||||
|
||||
import "google/protobuf/descriptor.proto"; |
||||
|
||||
package google.protobuf; |
||||
|
||||
message CSharpFileOptions { |
||||
|
||||
// Namespace for generated classes; defaults to the package. |
||||
optional string namespace = 1; |
||||
|
||||
// Name of the "umbrella" class used for metadata about all |
||||
// the messages within this file. Default is based on the name |
||||
// of the file. |
||||
optional string umbrella_classname = 2; |
||||
|
||||
// Whether classes should be public (true) or internal (false) |
||||
optional bool public_classes = 3 [default = true]; |
||||
|
||||
// Whether to generate a single file for everything within the |
||||
// .proto file (false), or one file per message (true). |
||||
// This option is not currently honored; please log a feature |
||||
// request if you really want it. |
||||
optional bool multiple_files = 4; |
||||
|
||||
// Whether to nest messages within a single umbrella class (true) |
||||
// or create the umbrella class as a peer, with messages as |
||||
// top-level classes in the namespace (false) |
||||
optional bool nest_classes = 5; |
||||
|
||||
// Generate appropriate support for Code Contracts |
||||
// (Ongoing; support should improve over time) |
||||
optional bool code_contracts = 6; |
||||
|
||||
// Create subdirectories for namespaces, e.g. namespace "Foo.Bar" |
||||
// would generate files within [output directory]/Foo/Bar |
||||
optional bool expand_namespace_directories = 7; |
||||
|
||||
// Generate attributes indicating non-CLS-compliance |
||||
optional bool cls_compliance = 8 [default = true]; |
||||
|
||||
// The extension that should be appended to the umbrella_classname when creating files. |
||||
optional string file_extension = 221 [default = ".cs"]; |
||||
|
||||
// A nested namespace for the umbrella class. Helpful for name collisions caused by |
||||
// umbrella_classname conflicting with an existing type. This will be automatically |
||||
// set to 'Proto' if a collision is detected with types being generated. This value |
||||
// is ignored when nest_classes == true |
||||
optional string umbrella_namespace = 222; |
||||
|
||||
// The output path for the source file(s) generated |
||||
optional string output_directory = 223 [default = "."]; |
||||
|
||||
// Will ignore the type generations and remove dependencies for the descriptor proto |
||||
// files that declare their package to be "google.protobuf" |
||||
optional bool ignore_google_protobuf = 224 [default = false]; |
||||
} |
||||
|
||||
extend FileOptions { |
||||
optional CSharpFileOptions csharp_file_options = 1000; |
||||
} |
||||
|
||||
extend FieldOptions { |
||||
optional CSharpFieldOptions csharp_field_options = 1000; |
||||
} |
||||
|
||||
message CSharpFieldOptions { |
||||
// Provides the ability to override the name of the property |
||||
// generated for this field. This is applied to all properties |
||||
// and methods to do with this field, including HasFoo, FooCount, |
||||
// FooList etc. |
||||
optional string property_name = 1; |
||||
} |
||||
// Extra options for C# generator |
||||
|
||||
import "google/protobuf/descriptor.proto"; |
||||
|
||||
package google.protobuf; |
||||
|
||||
message CSharpFileOptions { |
||||
|
||||
// Namespace for generated classes; defaults to the package. |
||||
optional string namespace = 1; |
||||
|
||||
// Name of the "umbrella" class used for metadata about all |
||||
// the messages within this file. Default is based on the name |
||||
// of the file. |
||||
optional string umbrella_classname = 2; |
||||
|
||||
// Whether classes should be public (true) or internal (false) |
||||
optional bool public_classes = 3 [default = true]; |
||||
|
||||
// Whether to generate a single file for everything within the |
||||
// .proto file (false), or one file per message (true). |
||||
// This option is not currently honored; please log a feature |
||||
// request if you really want it. |
||||
optional bool multiple_files = 4; |
||||
|
||||
// Whether to nest messages within a single umbrella class (true) |
||||
// or create the umbrella class as a peer, with messages as |
||||
// top-level classes in the namespace (false) |
||||
optional bool nest_classes = 5; |
||||
|
||||
// Generate appropriate support for Code Contracts |
||||
// (Ongoing; support should improve over time) |
||||
optional bool code_contracts = 6; |
||||
|
||||
// Create subdirectories for namespaces, e.g. namespace "Foo.Bar" |
||||
// would generate files within [output directory]/Foo/Bar |
||||
optional bool expand_namespace_directories = 7; |
||||
|
||||
// Generate attributes indicating non-CLS-compliance |
||||
optional bool cls_compliance = 8 [default = true]; |
||||
|
||||
// The extension that should be appended to the umbrella_classname when creating files. |
||||
optional string file_extension = 221 [default = ".cs"]; |
||||
|
||||
// A nested namespace for the umbrella class. Helpful for name collisions caused by |
||||
// umbrella_classname conflicting with an existing type. This will be automatically |
||||
// set to 'Proto' if a collision is detected with types being generated. This value |
||||
// is ignored when nest_classes == true |
||||
optional string umbrella_namespace = 222; |
||||
|
||||
// The output path for the source file(s) generated |
||||
optional string output_directory = 223 [default = "."]; |
||||
|
||||
// Will ignore the type generations and remove dependencies for the descriptor proto |
||||
// files that declare their package to be "google.protobuf" |
||||
optional bool ignore_google_protobuf = 224 [default = false]; |
||||
|
||||
// Controls how services are generated, GENERIC is the deprecated original implementation |
||||
// INTERFACE generates service interfaces only, RPCINTEROP generates interfaces and |
||||
// implementations using the included Windows RPC interop libarary. |
||||
optional CSharpServiceType service_generator_type = 225 [default = GENERIC]; |
||||
} |
||||
|
||||
enum CSharpServiceType { |
||||
// Generates the original Java generic service implementations |
||||
GENERIC = 1; |
||||
// Generates an interface for the service and nothing else |
||||
INTERFACE = 2; |
||||
// Generates an interface for the service and client/server wrappers for the interface |
||||
IRPCDISPATCH = 3; |
||||
} |
||||
|
||||
extend FileOptions { |
||||
optional CSharpFileOptions csharp_file_options = 1000; |
||||
} |
||||
|
||||
extend FieldOptions { |
||||
optional CSharpFieldOptions csharp_field_options = 1000; |
||||
} |
||||
|
||||
message CSharpFieldOptions { |
||||
// Provides the ability to override the name of the property |
||||
// generated for this field. This is applied to all properties |
||||
// and methods to do with this field, including HasFoo, FooCount, |
||||
// FooList etc. |
||||
optional string property_name = 1; |
||||
} |
||||
|
||||
message CSharpServiceOptions { |
||||
optional string interface_id = 1; |
||||
} |
||||
|
||||
extend ServiceOptions { |
||||
optional CSharpServiceOptions csharp_service_options = 1000; |
||||
} |
||||
|
||||
message CSharpMethodOptions { |
||||
optional int32 dispatch_id = 1; |
||||
} |
||||
|
||||
extend MethodOptions { |
||||
optional CSharpMethodOptions csharp_method_options = 1000; |
||||
} |
@ -0,0 +1,235 @@ |
||||
#region Copyright notice and license |
||||
// Protocol Buffers - Google's data interchange format |
||||
// Copyright 2008 Google Inc. All rights reserved. |
||||
// http://github.com/jskeet/dotnet-protobufs/ |
||||
// Original C++/Java/Python code: |
||||
// http://code.google.com/p/protobuf/ |
||||
// |
||||
// 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. |
||||
#endregion |
||||
|
||||
using System; |
||||
using System.Collections.Generic; |
||||
using Google.ProtocolBuffers.DescriptorProtos; |
||||
using Google.ProtocolBuffers.Descriptors; |
||||
|
||||
namespace Google.ProtocolBuffers.ProtoGen { |
||||
internal class ServiceGenerator : SourceGeneratorBase<ServiceDescriptor>, ISourceGenerator { |
||||
|
||||
readonly CSharpServiceType svcType; |
||||
ISourceGenerator _generator; |
||||
|
||||
internal ServiceGenerator(ServiceDescriptor descriptor) |
||||
: base(descriptor) { |
||||
svcType = descriptor.File.CSharpOptions.ServiceGeneratorType; |
||||
switch (svcType) { |
||||
case CSharpServiceType.GENERIC: |
||||
_generator = new GenericServiceGenerator(descriptor); |
||||
break; |
||||
case CSharpServiceType.INTERFACE: |
||||
_generator = new ServiceInterfaceGenerator(descriptor); |
||||
break; |
||||
case CSharpServiceType.IRPCDISPATCH: |
||||
_generator = new RpcServiceGenerator(descriptor); |
||||
break; |
||||
default: throw new ApplicationException("Unknown ServiceGeneratorType = " + svcType.ToString()); |
||||
} |
||||
} |
||||
|
||||
public void Generate(TextGenerator writer) { |
||||
_generator.Generate(writer); |
||||
} |
||||
|
||||
class ServiceInterfaceGenerator : SourceGeneratorBase<ServiceDescriptor>, ISourceGenerator { |
||||
|
||||
public ServiceInterfaceGenerator(ServiceDescriptor descriptor) |
||||
: base(descriptor) { |
||||
} |
||||
|
||||
public virtual void Generate(TextGenerator writer) { |
||||
|
||||
CSharpServiceOptions options = Descriptor.Options.GetExtension(CSharpOptions.CsharpServiceOptions); |
||||
if (options != null && options.HasInterfaceId) { |
||||
writer.WriteLine("[global::System.Runtime.InteropServices.GuidAttribute(\"{0}\")]", new Guid(options.InterfaceId)); |
||||
} |
||||
writer.WriteLine("{0} partial interface I{1} {{", ClassAccessLevel, Descriptor.Name); |
||||
writer.Indent(); |
||||
|
||||
foreach (MethodDescriptor method in Descriptor.Methods) |
||||
{ |
||||
CSharpMethodOptions mth = method.Options.GetExtension(CSharpOptions.CsharpMethodOptions); |
||||
if(mth.HasDispatchId) { |
||||
writer.WriteLine("[global::System.Runtime.InteropServices.DispId({0})]", mth.DispatchId); |
||||
} |
||||
writer.WriteLine("{0} {1}({2} {3});", GetClassName(method.OutputType), NameHelpers.UnderscoresToPascalCase(method.Name), GetClassName(method.InputType), NameHelpers.UnderscoresToCamelCase(method.InputType.Name)); |
||||
} |
||||
|
||||
writer.Outdent(); |
||||
writer.WriteLine("}"); |
||||
} |
||||
} |
||||
|
||||
class RpcServiceGenerator : ServiceInterfaceGenerator { |
||||
|
||||
public RpcServiceGenerator(ServiceDescriptor descriptor) |
||||
: base(descriptor) { |
||||
} |
||||
|
||||
public override void Generate(TextGenerator writer) |
||||
{ |
||||
base.Generate(writer); |
||||
|
||||
writer.WriteLine(); |
||||
|
||||
// CLIENT Proxy |
||||
{ |
||||
if (Descriptor.File.CSharpOptions.ClsCompliance) |
||||
writer.WriteLine("[global::System.CLSCompliant(false)]"); |
||||
writer.WriteLine("{0} partial class {1} : I{1}, pb::IRpcDispatch, global::System.IDisposable {{", ClassAccessLevel, Descriptor.Name); |
||||
writer.Indent(); |
||||
writer.WriteLine("private readonly bool dispose;"); |
||||
writer.WriteLine("private readonly pb::IRpcDispatch dispatch;"); |
||||
|
||||
writer.WriteLine("public {0}(pb::IRpcDispatch dispatch) : this(dispatch, true) {{", Descriptor.Name); |
||||
writer.WriteLine("}"); |
||||
writer.WriteLine("public {0}(pb::IRpcDispatch dispatch, bool dispose) {{", Descriptor.Name); |
||||
writer.WriteLine(" if (null == (this.dispatch = dispatch)) throw new global::System.ArgumentNullException();"); |
||||
writer.WriteLine(" this.dispose = dispose && dispatch is global::System.IDisposable;"); |
||||
writer.WriteLine("}"); |
||||
writer.WriteLine(); |
||||
|
||||
writer.WriteLine("public void Dispose() {"); |
||||
writer.WriteLine(" if (dispose) ((global::System.IDisposable)dispatch).Dispose();"); |
||||
writer.WriteLine("}"); |
||||
writer.WriteLine(); |
||||
writer.WriteLine("TMessage pb::IRpcDispatch.CallMethod<TMessage, TBuilder>(string method, pb::IMessageLite request, pb::IBuilderLite<TMessage, TBuilder> response) {"); |
||||
writer.WriteLine(" return dispatch.CallMethod(method, request, response);"); |
||||
writer.WriteLine("}"); |
||||
writer.WriteLine(); |
||||
|
||||
foreach (MethodDescriptor method in Descriptor.Methods) { |
||||
writer.WriteLine("public {0} {1}({2} {3}) {{", GetClassName(method.OutputType), NameHelpers.UnderscoresToPascalCase(method.Name), GetClassName(method.InputType), NameHelpers.UnderscoresToCamelCase(method.InputType.Name)); |
||||
writer.WriteLine(" return dispatch.CallMethod(\"{0}\", {1}, {2}.CreateBuilder());", |
||||
method.Name, |
||||
NameHelpers.UnderscoresToCamelCase(method.InputType.Name), |
||||
GetClassName(method.OutputType) |
||||
); |
||||
writer.WriteLine("}"); |
||||
writer.WriteLine(); |
||||
} |
||||
} |
||||
// SERVER - DISPATCH |
||||
{ |
||||
if (Descriptor.File.CSharpOptions.ClsCompliance) |
||||
writer.WriteLine("[global::System.CLSCompliant(false)]"); |
||||
writer.WriteLine("public partial class Dispatch : pb::IRpcDispatch, global::System.IDisposable {"); |
||||
writer.Indent(); |
||||
writer.WriteLine("private readonly bool dispose;"); |
||||
writer.WriteLine("private readonly I{0} implementation;", Descriptor.Name); |
||||
|
||||
writer.WriteLine("public Dispatch(I{0} implementation) : this(implementation, true) {{", Descriptor.Name); |
||||
writer.WriteLine("}"); |
||||
writer.WriteLine("public Dispatch(I{0} implementation, bool dispose) {{", Descriptor.Name); |
||||
writer.WriteLine(" if (null == (this.implementation = implementation)) throw new global::System.ArgumentNullException();"); |
||||
writer.WriteLine(" this.dispose = dispose && implementation is global::System.IDisposable;"); |
||||
writer.WriteLine("}"); |
||||
writer.WriteLine(); |
||||
|
||||
writer.WriteLine("public void Dispose() {"); |
||||
writer.WriteLine(" if (dispose) ((global::System.IDisposable)implementation).Dispose();"); |
||||
writer.WriteLine("}"); |
||||
writer.WriteLine(); |
||||
|
||||
writer.WriteLine("public TMessage CallMethod<TMessage, TBuilder>(string methodName, pb::IMessageLite request, pb::IBuilderLite<TMessage, TBuilder> response)"); |
||||
writer.WriteLine(" where TMessage : IMessageLite<TMessage, TBuilder>"); |
||||
writer.WriteLine(" where TBuilder : IBuilderLite<TMessage, TBuilder> {"); |
||||
writer.Indent(); |
||||
writer.WriteLine("switch(methodName) {"); |
||||
writer.Indent(); |
||||
|
||||
foreach (MethodDescriptor method in Descriptor.Methods) { |
||||
writer.WriteLine("case \"{0}\": return response.MergeFrom(implementation.{1}(({2})request)).Build();", method.Name, NameHelpers.UnderscoresToPascalCase(method.Name), GetClassName(method.InputType)); |
||||
} |
||||
writer.WriteLine("default: throw new global::System.MissingMethodException(typeof(ISearchService).FullName, methodName);"); |
||||
writer.Outdent(); |
||||
writer.WriteLine("}");//end switch |
||||
writer.Outdent(); |
||||
writer.WriteLine("}");//end invoke |
||||
writer.Outdent(); |
||||
writer.WriteLine("}");//end server |
||||
} |
||||
// SERVER - STUB |
||||
{ |
||||
if (Descriptor.File.CSharpOptions.ClsCompliance) |
||||
writer.WriteLine("[global::System.CLSCompliant(false)]"); |
||||
writer.WriteLine("public partial class ServerStub : pb::IRpcServerStub, global::System.IDisposable {"); |
||||
writer.Indent(); |
||||
writer.WriteLine("private readonly bool dispose;"); |
||||
writer.WriteLine("private readonly pb::IRpcDispatch implementation;", Descriptor.Name); |
||||
|
||||
writer.WriteLine("public ServerStub(I{0} implementation) : this(implementation, true) {{", Descriptor.Name); |
||||
writer.WriteLine("}"); |
||||
writer.WriteLine("public ServerStub(I{0} implementation, bool dispose) : this(new Dispatch(implementation, dispose), dispose) {{", Descriptor.Name); |
||||
writer.WriteLine("}"); |
||||
|
||||
writer.WriteLine("public ServerStub(pb::IRpcDispatch implementation) : this(implementation, true) {"); |
||||
writer.WriteLine("}"); |
||||
writer.WriteLine("public ServerStub(pb::IRpcDispatch implementation, bool dispose) {"); |
||||
writer.WriteLine(" if (null == (this.implementation = implementation)) throw new global::System.ArgumentNullException();"); |
||||
writer.WriteLine(" this.dispose = dispose && implementation is global::System.IDisposable;"); |
||||
writer.WriteLine("}"); |
||||
writer.WriteLine(); |
||||
|
||||
writer.WriteLine("public void Dispose() {"); |
||||
writer.WriteLine(" if (dispose) ((global::System.IDisposable)implementation).Dispose();"); |
||||
writer.WriteLine("}"); |
||||
writer.WriteLine(); |
||||
|
||||
writer.WriteLine("public pb::IMessageLite CallMethod(string methodName, pb::CodedInputStream input, pb::ExtensionRegistry registry) {{", Descriptor.Name); |
||||
writer.Indent(); |
||||
writer.WriteLine("switch(methodName) {"); |
||||
writer.Indent(); |
||||
|
||||
foreach (MethodDescriptor method in Descriptor.Methods) |
||||
{ |
||||
writer.WriteLine("case \"{0}\": return implementation.CallMethod(methodName, {1}.ParseFrom(input, registry), {2}.CreateBuilder());", method.Name, GetClassName(method.InputType), GetClassName(method.OutputType)); |
||||
} |
||||
writer.WriteLine("default: throw new global::System.MissingMethodException(typeof(ISearchService).FullName, methodName);"); |
||||
writer.Outdent(); |
||||
writer.WriteLine("}");//end switch |
||||
writer.Outdent(); |
||||
writer.WriteLine("}");//end invoke |
||||
writer.Outdent(); |
||||
writer.WriteLine("}");//end server |
||||
} |
||||
|
||||
writer.Outdent(); |
||||
writer.WriteLine("}"); |
||||
} |
||||
} |
||||
} |
||||
} |
File diff suppressed because it is too large
Load Diff
Loading…
Reference in new issue