Beispiel #1
0
            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));
                }
                WriteGeneratedCodeAttributes(writer);
                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("}");
            }
Beispiel #2
0
            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("[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]");
                    WriteGeneratedCodeAttributes(writer);
                    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("  pb::ThrowHelper.ThrowIfNull(this.dispatch = dispatch, \"dispatch\");");
                    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("[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]");
                    WriteGeneratedCodeAttributes(writer);
                    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("  pb::ThrowHelper.ThrowIfNull(this.implementation = implementation, \"implementation\");");
                    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 : pb::IMessageLite<TMessage, TBuilder>");
                    writer.WriteLine("  where TBuilder : pb::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 pb::ThrowHelper.CreateMissingMethod(typeof(I{0}), methodName);", Descriptor.Name);
                    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("[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]");
                    WriteGeneratedCodeAttributes(writer);
                    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("  pb::ThrowHelper.ThrowIfNull(this.implementation = implementation, \"implementation\");");
                    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::ICodedInputStream 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 pb::ThrowHelper.CreateMissingMethod(typeof(I{0}), methodName);", Descriptor.Name);
                    writer.Outdent();
                    writer.WriteLine("}"); //end switch
                    writer.Outdent();
                    writer.WriteLine("}"); //end invoke
                    writer.Outdent();
                    writer.WriteLine("}"); //end server
                }

                writer.Outdent();
                writer.WriteLine("}");
            }
        private void GenerateMessageSerializationMethods(TextGenerator writer)
        {
            List <FieldDescriptor> sortedFields = new List <FieldDescriptor>(Descriptor.Fields);

            sortedFields.Sort((f1, f2) => f1.FieldNumber.CompareTo(f2.FieldNumber));

            List <DescriptorProto.Types.ExtensionRange> sortedExtensions =
                new List <DescriptorProto.Types.ExtensionRange>(Descriptor.Proto.ExtensionRangeList);

            sortedExtensions.Sort((r1, r2) => (r1.Start.CompareTo(r2.Start)));

            writer.WriteLine("public override void WriteTo(pb::ICodedOutputStream output) {");
            writer.Indent();
            // Make sure we've computed the serialized length, so that packed fields are generated correctly.
            writer.WriteLine("CalcSerializedSize();");
            writer.WriteLine("string[] field_names = _{0}FieldNames;", NameHelpers.UnderscoresToCamelCase(ClassName));
            if (Descriptor.Proto.ExtensionRangeList.Count > 0)
            {
                writer.WriteLine(
                    "pb::ExtendableMessage{1}<{0}, {0}.Builder>.ExtensionWriter extensionWriter = CreateExtensionWriter(this);",
                    ClassName, RuntimeSuffix);
            }

            // Merge the fields and the extension ranges, both sorted by field number.
            for (int i = 0, j = 0; i < Descriptor.Fields.Count || j < sortedExtensions.Count;)
            {
                if (i == Descriptor.Fields.Count)
                {
                    GenerateSerializeOneExtensionRange(writer, sortedExtensions[j++]);
                }
                else if (j == sortedExtensions.Count)
                {
                    GenerateSerializeOneField(writer, sortedFields[i++]);
                }
                else if (sortedFields[i].FieldNumber < sortedExtensions[j].Start)
                {
                    GenerateSerializeOneField(writer, sortedFields[i++]);
                }
                else
                {
                    GenerateSerializeOneExtensionRange(writer, sortedExtensions[j++]);
                }
            }

            if (!UseLiteRuntime)
            {
                if (Descriptor.Proto.Options.MessageSetWireFormat)
                {
                    writer.WriteLine("UnknownFields.WriteAsMessageSetTo(output);");
                }
                else
                {
                    writer.WriteLine("UnknownFields.WriteTo(output);");
                }
            }

            writer.Outdent();
            writer.WriteLine("}");
            writer.WriteLine();
            writer.WriteLine("private int memoizedSerializedSize = -1;");
            writer.WriteLine("public override int SerializedSize {");
            writer.Indent();
            writer.WriteLine("get {");
            writer.Indent();
            writer.WriteLine("int size = memoizedSerializedSize;");
            writer.WriteLine("if (size != -1) return size;");
            writer.WriteLine("return CalcSerializedSize();");
            writer.Outdent();
            writer.WriteLine("}");
            writer.Outdent();
            writer.WriteLine("}");
            writer.WriteLine();

            writer.WriteLine("private int CalcSerializedSize() {");
            writer.Indent();
            writer.WriteLine("int size = memoizedSerializedSize;");
            writer.WriteLine("if (size != -1) return size;");
            writer.WriteLine();
            writer.WriteLine("size = 0;");
            foreach (FieldDescriptor field in Descriptor.Fields)
            {
                CreateFieldGenerator(field).GenerateSerializedSizeCode(writer);
            }
            if (Descriptor.Proto.ExtensionRangeCount > 0)
            {
                writer.WriteLine("size += ExtensionsSerializedSize;");
            }

            if (!UseLiteRuntime)
            {
                if (Descriptor.Options.MessageSetWireFormat)
                {
                    writer.WriteLine("size += UnknownFields.SerializedSizeAsMessageSet;");
                }
                else
                {
                    writer.WriteLine("size += UnknownFields.SerializedSize;");
                }
            }
            writer.WriteLine("memoizedSerializedSize = size;");
            writer.WriteLine("return size;");
            writer.Outdent();
            writer.WriteLine("}");
        }
        private void GenerateBuilderParsingMethods(TextGenerator writer)
        {
            List <FieldDescriptor> sortedFields = new List <FieldDescriptor>(Descriptor.Fields);

            sortedFields.Sort((f1, f2) => f1.FieldNumber.CompareTo(f2.FieldNumber));

            writer.WriteLine("public override Builder MergeFrom(pb::ICodedInputStream input) {");
            writer.WriteLine("  return MergeFrom(input, pb::ExtensionRegistry.Empty);");
            writer.WriteLine("}");
            writer.WriteLine();
            writer.WriteLine(
                "public override Builder MergeFrom(pb::ICodedInputStream input, pb::ExtensionRegistry extensionRegistry) {");
            writer.Indent();
            writer.WriteLine("PrepareBuilder();");
            if (!UseLiteRuntime)
            {
                writer.WriteLine("pb::UnknownFieldSet.Builder unknownFields = null;");
            }
            writer.WriteLine("uint tag;");
            writer.WriteLine("string field_name;");
            writer.WriteLine("while (input.ReadTag(out tag, out field_name)) {");
            writer.Indent();
            writer.WriteLine("if(tag == 0 && field_name != null) {");
            writer.Indent();
            //if you change from StringComparer.Ordinal, the array sort in FieldNames { get; } must also change
            writer.WriteLine(
                "int field_ordinal = global::System.Array.BinarySearch(_{0}FieldNames, field_name, global::System.StringComparer.Ordinal);",
                NameHelpers.UnderscoresToCamelCase(ClassName));
            writer.WriteLine("if(field_ordinal >= 0)");
            writer.WriteLine("  tag = _{0}FieldTags[field_ordinal];", NameHelpers.UnderscoresToCamelCase(ClassName));
            writer.WriteLine("else {");
            if (!UseLiteRuntime)
            {
                writer.WriteLine("  if (unknownFields == null) {"); // First unknown field - create builder now
                writer.WriteLine("    unknownFields = pb::UnknownFieldSet.CreateBuilder(this.UnknownFields);");
                writer.WriteLine("  }");
            }
            writer.WriteLine("  ParseUnknownField(input, {0}extensionRegistry, tag, field_name);",
                             UseLiteRuntime ? "" : "unknownFields, ");
            writer.WriteLine("  continue;");
            writer.WriteLine("}");
            writer.Outdent();
            writer.WriteLine("}");

            writer.WriteLine("switch (tag) {");
            writer.Indent();
            writer.WriteLine("case 0: {"); // 0 signals EOF / limit reached
            writer.WriteLine("  throw pb::InvalidProtocolBufferException.InvalidTag();");
            writer.WriteLine("}");
            writer.WriteLine("default: {");
            writer.WriteLine("  if (pb::WireFormat.IsEndGroupTag(tag)) {");
            if (!UseLiteRuntime)
            {
                writer.WriteLine("    if (unknownFields != null) {");
                writer.WriteLine("      this.UnknownFields = unknownFields.Build();");
                writer.WriteLine("    }");
            }
            writer.WriteLine("    return this;"); // it's an endgroup tag
            writer.WriteLine("  }");
            if (!UseLiteRuntime)
            {
                writer.WriteLine("  if (unknownFields == null) {"); // First unknown field - create builder now
                writer.WriteLine("    unknownFields = pb::UnknownFieldSet.CreateBuilder(this.UnknownFields);");
                writer.WriteLine("  }");
            }
            writer.WriteLine("  ParseUnknownField(input, {0}extensionRegistry, tag, field_name);",
                             UseLiteRuntime ? "" : "unknownFields, ");
            writer.WriteLine("  break;");
            writer.WriteLine("}");
            foreach (FieldDescriptor field in sortedFields)
            {
                WireFormat.WireType wt = WireFormat.GetWireType(field.FieldType);
                uint tag = WireFormat.MakeTag(field.FieldNumber, wt);

                if (field.IsRepeated &&
                    (wt == WireFormat.WireType.Varint || wt == WireFormat.WireType.Fixed32 ||
                     wt == WireFormat.WireType.Fixed64))
                {
                    writer.WriteLine("case {0}:",
                                     WireFormat.MakeTag(field.FieldNumber, WireFormat.WireType.LengthDelimited));
                }

                writer.WriteLine("case {0}: {{", tag);
                writer.Indent();
                CreateFieldGenerator(field).GenerateParsingCode(writer);
                writer.WriteLine("break;");
                writer.Outdent();
                writer.WriteLine("}");
            }
            writer.Outdent();
            writer.WriteLine("}");
            writer.Outdent();
            writer.WriteLine("}");
            writer.WriteLine();
            if (!UseLiteRuntime)
            {
                writer.WriteLine("if (unknownFields != null) {");
                writer.WriteLine("  this.UnknownFields = unknownFields.Build();");
                writer.WriteLine("}");
            }
            writer.WriteLine("return this;");
            writer.Outdent();
            writer.WriteLine("}");
            writer.WriteLine();
        }
        public void Generate(TextGenerator writer)
        {
            if (Descriptor.File.CSharpOptions.AddSerializable)
            {
                writer.WriteLine("[global::System.SerializableAttribute()]");
            }
            writer.WriteLine("[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]");
            WriteGeneratedCodeAttributes(writer);
            writer.WriteLine("{0} sealed partial class {1} : pb::{2}Message{3}<{1}, {1}.Builder> {{",
                             ClassAccessLevel, ClassName,
                             Descriptor.Proto.ExtensionRangeCount > 0 ? "Extendable" : "Generated",
                             RuntimeSuffix);
            writer.Indent();
            if (Descriptor.File.CSharpOptions.GeneratePrivateCtor)
            {
                writer.WriteLine("private {0}() {{ }}", ClassName);
            }
            // Must call MakeReadOnly() to make sure all lists are made read-only
            writer.WriteLine("private static readonly {0} defaultInstance = new {0}().MakeReadOnly();", ClassName);

            if (OptimizeSpeed)
            {
                writer.WriteLine("private static readonly string[] _{0}FieldNames = new string[] {{ {2}{1}{2} }};",
                                 NameHelpers.UnderscoresToCamelCase(ClassName), String.Join("\", \"", FieldNames),
                                 FieldNames.Length > 0 ? "\"" : "");
                List <string> tags = new List <string>();
                foreach (string name in FieldNames)
                {
                    tags.Add(WireFormat.MakeTag(Descriptor.FindFieldByName(name)).ToString());
                }

                writer.WriteLine("private static readonly uint[] _{0}FieldTags = new uint[] {{ {1} }};",
                                 NameHelpers.UnderscoresToCamelCase(ClassName), String.Join(", ", tags.ToArray()));
            }
            writer.WriteLine("public static {0} DefaultInstance {{", ClassName);
            writer.WriteLine("  get { return defaultInstance; }");
            writer.WriteLine("}");
            writer.WriteLine();
            writer.WriteLine("public override {0} DefaultInstanceForType {{", ClassName);
            writer.WriteLine("  get { return DefaultInstance; }");
            writer.WriteLine("}");
            writer.WriteLine();
            writer.WriteLine("protected override {0} ThisMessage {{", ClassName);
            writer.WriteLine("  get { return this; }");
            writer.WriteLine("}");
            writer.WriteLine();
            if (!UseLiteRuntime)
            {
                writer.WriteLine("public static pbd::MessageDescriptor Descriptor {");
                writer.WriteLine("  get {{ return {0}.internal__{1}__Descriptor; }}",
                                 DescriptorUtil.GetFullUmbrellaClassName(Descriptor),
                                 GetUniqueFileScopeIdentifier(Descriptor));
                writer.WriteLine("}");
                writer.WriteLine();
                writer.WriteLine(
                    "protected override pb::FieldAccess.FieldAccessorTable<{0}, {0}.Builder> InternalFieldAccessors {{",
                    ClassName);
                writer.WriteLine("  get {{ return {0}.internal__{1}__FieldAccessorTable; }}",
                                 DescriptorUtil.GetFullUmbrellaClassName(Descriptor),
                                 GetUniqueFileScopeIdentifier(Descriptor));
                writer.WriteLine("}");
                writer.WriteLine();
            }

            // Extensions don't need to go in an extra nested type
            WriteChildren(writer, null, Descriptor.Extensions);

            if (Descriptor.EnumTypes.Count + Descriptor.NestedTypes.Count > 0)
            {
                writer.WriteLine("#region Nested types");
                writer.WriteLine("[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]");
                WriteGeneratedCodeAttributes(writer);
                writer.WriteLine("public static partial class Types {");
                writer.Indent();
                WriteChildren(writer, null, Descriptor.EnumTypes);
                WriteChildren(writer, null, Descriptor.NestedTypes);
                writer.Outdent();
                writer.WriteLine("}");
                writer.WriteLine("#endregion");
                writer.WriteLine();
            }

            foreach (FieldDescriptor fieldDescriptor in Descriptor.Fields)
            {
                if (Descriptor.File.CSharpOptions.ClsCompliance && GetFieldConstantName(fieldDescriptor).StartsWith("_"))
                {
                    writer.WriteLine("[global::System.CLSCompliant(false)]");
                }

                // Rats: we lose the debug comment here :(
                writer.WriteLine("public const int {0} = {1};", GetFieldConstantName(fieldDescriptor),
                                 fieldDescriptor.FieldNumber);
                CreateFieldGenerator(fieldDescriptor).GenerateMembers(writer);
                writer.WriteLine();
            }

            if (OptimizeSpeed)
            {
                GenerateIsInitialized(writer);
                GenerateMessageSerializationMethods(writer);
            }
            if (UseLiteRuntime)
            {
                GenerateLiteRuntimeMethods(writer);
            }

            GenerateParseFromMethods(writer);
            GenerateBuilder(writer);

            // Force the static initialization code for the file to run, since it may
            // initialize static variables declared in this class.
            writer.WriteLine("static {0}() {{", ClassName);
            // We call object.ReferenceEquals() just to make it a valid statement on its own.
            // Another option would be GetType(), but that causes problems in DescriptorProtoFile,
            // where the bootstrapping is somewhat recursive - type initializers call
            // each other, effectively. We temporarily see Descriptor as null.
            writer.WriteLine("  object.ReferenceEquals({0}.Descriptor, null);",
                             DescriptorUtil.GetFullUmbrellaClassName(Descriptor));
            writer.WriteLine("}");

            writer.Outdent();
            writer.WriteLine("}");
            writer.WriteLine();
        }