diff options
author | Jon Skeet <skeet@pobox.com> | 2010-12-12 12:37:30 +0000 |
---|---|---|
committer | Jon Skeet <skeet@pobox.com> | 2010-12-12 12:37:30 +0000 |
commit | 1738462b7fbaf806a3bc28b52b61a037b45a73f4 (patch) | |
tree | c29623a454f41741a1cd0f265709cd4cd92647a0 /src/ProtoGen | |
parent | 0c58d060f7e919439210fff5ee107e023b1c8199 (diff) | |
parent | 00ca60805301f14ff4abc70cef5cd6df0b3f8b67 (diff) | |
download | protobuf-1738462b7fbaf806a3bc28b52b61a037b45a73f4.tar.gz protobuf-1738462b7fbaf806a3bc28b52b61a037b45a73f4.tar.bz2 protobuf-1738462b7fbaf806a3bc28b52b61a037b45a73f4.zip |
First commit of lite code - more to come
Diffstat (limited to 'src/ProtoGen')
-rw-r--r-- | src/ProtoGen/EnumFieldGenerator.cs | 24 | ||||
-rw-r--r-- | src/ProtoGen/ExtensionGenerator.cs | 57 | ||||
-rw-r--r-- | src/ProtoGen/FieldGeneratorBase.cs | 34 | ||||
-rw-r--r-- | src/ProtoGen/Helpers.cs | 6 | ||||
-rw-r--r-- | src/ProtoGen/IFieldSourceGenerator.cs | 4 | ||||
-rw-r--r-- | src/ProtoGen/MessageFieldGenerator.cs | 13 | ||||
-rw-r--r-- | src/ProtoGen/MessageGenerator.cs | 196 | ||||
-rw-r--r-- | src/ProtoGen/PrimitiveFieldGenerator.cs | 12 | ||||
-rw-r--r-- | src/ProtoGen/RepeatedEnumFieldGenerator.cs | 27 | ||||
-rw-r--r-- | src/ProtoGen/RepeatedMessageFieldGenerator.cs | 17 | ||||
-rw-r--r-- | src/ProtoGen/RepeatedPrimitiveFieldGenerator.cs | 17 | ||||
-rw-r--r-- | src/ProtoGen/SourceGeneratorBase.cs | 12 | ||||
-rw-r--r-- | src/ProtoGen/UmbrellaClassGenerator.cs | 36 |
13 files changed, 360 insertions, 95 deletions
diff --git a/src/ProtoGen/EnumFieldGenerator.cs b/src/ProtoGen/EnumFieldGenerator.cs index 5fc24b56..6cd59869 100644 --- a/src/ProtoGen/EnumFieldGenerator.cs +++ b/src/ProtoGen/EnumFieldGenerator.cs @@ -88,10 +88,12 @@ namespace Google.ProtocolBuffers.ProtoGen { // TODO(jonskeet): Make a more efficient way of doing this writer.WriteLine("int rawValue = input.ReadEnum();"); writer.WriteLine("if (!global::System.Enum.IsDefined(typeof({0}), rawValue)) {{", TypeName); - writer.WriteLine(" if (unknownFields == null) {"); // First unknown field - create builder now - writer.WriteLine(" unknownFields = pb::UnknownFieldSet.CreateBuilder(this.UnknownFields);"); - writer.WriteLine(" }"); - writer.WriteLine(" unknownFields.MergeVarintField({0}, (ulong) rawValue);", Number); + 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(" unknownFields.MergeVarintField({0}, (ulong) rawValue);", Number); + } writer.WriteLine("} else {"); writer.WriteLine(" {0} = ({1}) rawValue;", PropertyName, TypeName); writer.WriteLine("}"); @@ -106,7 +108,19 @@ namespace Google.ProtocolBuffers.ProtoGen { public void GenerateSerializedSizeCode(TextGenerator writer) { writer.WriteLine("if (Has{0}) {{", PropertyName); writer.WriteLine(" size += pb::CodedOutputStream.ComputeEnumSize({0}, (int) {1});", Number, PropertyName); - writer.WriteLine("}"); + writer.WriteLine("}"); + } + + public override void WriteHash(TextGenerator writer) { + writer.WriteLine("if (has{0}) hash ^= {1}_.GetHashCode();", PropertyName, Name); + } + + public override void WriteEquals(TextGenerator writer) { + writer.WriteLine("if (has{0} != other.has{0} || (has{0} && !{1}_.Equals(other.{1}_))) return false;", PropertyName, Name); + } + + public override void WriteToString(TextGenerator writer) { + writer.WriteLine("PrintField(\"{0}\", has{1}, {2}_, writer);", Descriptor.Name, PropertyName, Name); } } } diff --git a/src/ProtoGen/ExtensionGenerator.cs b/src/ProtoGen/ExtensionGenerator.cs index 6970e69a..57713bf7 100644 --- a/src/ProtoGen/ExtensionGenerator.cs +++ b/src/ProtoGen/ExtensionGenerator.cs @@ -32,16 +32,20 @@ // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #endregion +using System; +using System.Globalization; using Google.ProtocolBuffers.Descriptors; namespace Google.ProtocolBuffers.ProtoGen { - internal class ExtensionGenerator : SourceGeneratorBase<FieldDescriptor>, ISourceGenerator { + internal class ExtensionGenerator : FieldGeneratorBase, ISourceGenerator { + private readonly string extends; private readonly string scope; private readonly string type; private readonly string name; - internal ExtensionGenerator(FieldDescriptor descriptor) : base(descriptor) { + internal ExtensionGenerator(FieldDescriptor descriptor) + : base(descriptor) { if (Descriptor.ExtensionScope != null) { scope = GetClassName(Descriptor.ExtensionScope); } else { @@ -58,14 +62,24 @@ namespace Google.ProtocolBuffers.ProtoGen { type = DescriptorUtil.GetMappedTypeName(Descriptor.MappedType); break; } + extends = GetClassName(Descriptor.ContainingType); name = Descriptor.CSharpOptions.PropertyName; } public void Generate(TextGenerator writer) { - writer.WriteLine ("public const int {0} = {1};", GetFieldConstantName(Descriptor), Descriptor.FieldNumber); - if (Descriptor.IsRepeated) { - if (!Descriptor.IsCLSCompliant && Descriptor.File.CSharpOptions.ClsCompliance) - { + writer.WriteLine("public const int {0} = {1};", GetFieldConstantName(Descriptor), Descriptor.FieldNumber); + + if (UseLiteRuntime) { + if (Descriptor.MappedType == MappedType.Message && Descriptor.MessageType.Options.MessageSetWireFormat) { + throw new ArgumentException("option message_set_wire_format = true; is not supported in Lite runtime extensions."); + } + if (!Descriptor.IsCLSCompliant && Descriptor.File.CSharpOptions.ClsCompliance) { + writer.WriteLine("[global::System.CLSCompliant(false)]"); + } + writer.WriteLine("{0} static pb::{4}<{1}, {2}> {3};", ClassAccessLevel, extends, type, name, + Descriptor.IsRepeated ? "GeneratedRepeatExtensionLite" : "GeneratedExtensionLite"); + } else if (Descriptor.IsRepeated) { + if (!Descriptor.IsCLSCompliant && Descriptor.File.CSharpOptions.ClsCompliance) { writer.WriteLine("[global::System.CLSCompliant(false)]"); } writer.WriteLine("{0} static pb::GeneratedExtensionBase<scg::IList<{1}>> {2};", ClassAccessLevel, type, name); @@ -78,7 +92,27 @@ namespace Google.ProtocolBuffers.ProtoGen { } internal void GenerateStaticVariableInitializers(TextGenerator writer) { - if (Descriptor.IsRepeated) { + if (UseLiteRuntime) { + writer.WriteLine("{0}.{1} = ", scope, name); + writer.Indent(); + writer.WriteLine("new pb::{0}<{1}, {2}>(", Descriptor.IsRepeated ? "GeneratedRepeatExtensionLite" : "GeneratedExtensionLite", extends, type); + writer.Indent(); + writer.WriteLine("\"{0}\",", Descriptor.FullName); + writer.WriteLine("{0}.DefaultInstance,", extends); + if(!Descriptor.IsRepeated) + writer.WriteLine("{0},", Descriptor.HasDefaultValue ? DefaultValue : IsNullableType ? "null" : "default(" + type + ")"); + writer.WriteLine("{0},", (Descriptor.MappedType == MappedType.Message) ? type + ".DefaultInstance" : "null"); + writer.WriteLine("{0},", (Descriptor.MappedType == MappedType.Enum) ? "new EnumLiteMap<" + type + ">()" : "null"); + writer.WriteLine("{0}.{1}FieldNumber,", scope, name); + writer.Write("pbd::FieldType.{0}", Descriptor.FieldType); + if (Descriptor.IsRepeated) { + writer.WriteLine(","); + writer.Write(Descriptor.IsPacked ? "true" : "false"); + } + writer.Outdent(); + writer.WriteLine(");"); + writer.Outdent(); + } else if (Descriptor.IsRepeated) { writer.WriteLine("{0}.{1} = pb::GeneratedRepeatExtension<{2}>.CreateInstance({0}.Descriptor.Extensions[{3}]);", scope, name, type, Descriptor.Index); } else { writer.WriteLine("{0}.{1} = pb::GeneratedSingleExtension<{2}>.CreateInstance({0}.Descriptor.Extensions[{3}]);", scope, name, type, Descriptor.Index); @@ -88,5 +122,14 @@ namespace Google.ProtocolBuffers.ProtoGen { internal void GenerateExtensionRegistrationCode(TextGenerator writer) { writer.WriteLine("registry.Add({0}.{1});", scope, name); } + + public override void WriteHash(TextGenerator writer) { + } + + public override void WriteEquals(TextGenerator writer) { + } + + public override void WriteToString(TextGenerator writer) { + } } } diff --git a/src/ProtoGen/FieldGeneratorBase.cs b/src/ProtoGen/FieldGeneratorBase.cs index 1c273b18..45a096a0 100644 --- a/src/ProtoGen/FieldGeneratorBase.cs +++ b/src/ProtoGen/FieldGeneratorBase.cs @@ -42,6 +42,10 @@ namespace Google.ProtocolBuffers.ProtoGen { : base(descriptor) { } + public abstract void WriteHash(TextGenerator writer); + public abstract void WriteEquals(TextGenerator writer); + public abstract void WriteToString(TextGenerator writer); + private static bool AllPrintableAscii(string text) { foreach (char c in text) { if (c < 0x20 || c > 0x7e) { @@ -51,6 +55,7 @@ namespace Google.ProtocolBuffers.ProtoGen { return true; } + /// <remarks>Copy exists in ExtensionGenerator.cs</remarks> protected string DefaultValue { get { string suffix = ""; @@ -72,11 +77,30 @@ namespace Google.ProtocolBuffers.ProtoGen { case FieldType.UInt32: case FieldType.UInt64: case FieldType.Fixed32: - case FieldType.Fixed64: + case FieldType.Fixed64: + { // The simple Object.ToString converts using the current culture. // We want to always use the invariant culture so it's predictable. IConvertible value = (IConvertible) Descriptor.DefaultValue; + //a few things that must be handled explicitly + if (Descriptor.FieldType == FieldType.Double && value is double) { + if (double.IsNaN((double) value)) + return "double.NaN"; + if (double.IsPositiveInfinity((double) value)) + return "double.PositiveInfinity"; + if (double.IsNegativeInfinity((double) value)) + return "double.NegativeInfinity"; + } + else if (Descriptor.FieldType == FieldType.Float && value is float) { + if (float.IsNaN((float)value)) + return "float.NaN"; + if (float.IsPositiveInfinity((float)value)) + return "float.PositiveInfinity"; + if (float.IsNegativeInfinity((float)value)) + return "float.NegativeInfinity"; + } return value.ToString(CultureInfo.InvariantCulture) + suffix; + } case FieldType.Bool: return (bool) Descriptor.DefaultValue ? "true" : "false"; @@ -84,6 +108,10 @@ namespace Google.ProtocolBuffers.ProtoGen { if (!Descriptor.HasDefaultValue) { return "pb::ByteString.Empty"; } + if (UseLiteRuntime && Descriptor.DefaultValue is ByteString) { + string temp = Convert.ToBase64String(((ByteString)Descriptor.DefaultValue).ToByteArray()); + return String.Format("ByteString.FromBase64(\"{0}\")", temp); + } return string.Format("(pb::ByteString) {0}.Descriptor.Fields[{1}].DefaultValue", GetClassName(Descriptor.ContainingType), Descriptor.Index); case FieldType.String: if (AllPrintableAscii(Descriptor.Proto.DefaultValue)) { @@ -95,6 +123,10 @@ namespace Google.ProtocolBuffers.ProtoGen { .Replace("\"", "\\\"") + "\""; } + if (UseLiteRuntime && Descriptor.DefaultValue is String) { + string temp = Convert.ToBase64String(System.Text.Encoding.UTF8.GetBytes((String)Descriptor.DefaultValue)); + return String.Format("ByteString.FromBase64(\"{0}\").ToStringUtf8()", temp); + } return string.Format("(string) {0}.Descriptor.Fields[{1}].DefaultValue", GetClassName(Descriptor.ContainingType), Descriptor.Index); case FieldType.Enum: return TypeName + "." + ((EnumValueDescriptor) Descriptor.DefaultValue).Name; diff --git a/src/ProtoGen/Helpers.cs b/src/ProtoGen/Helpers.cs index 7fb7d8fd..6b6e3163 100644 --- a/src/ProtoGen/Helpers.cs +++ b/src/ProtoGen/Helpers.cs @@ -38,11 +38,5 @@ namespace Google.ProtocolBuffers.ProtoGen { /// Helpers to resolve class names etc. /// </summary> internal static class Helpers { - internal static void WriteNamespaces(TextGenerator writer) { - writer.WriteLine("using pb = global::Google.ProtocolBuffers;"); - writer.WriteLine("using pbc = global::Google.ProtocolBuffers.Collections;"); - writer.WriteLine("using pbd = global::Google.ProtocolBuffers.Descriptors;"); - writer.WriteLine("using scg = global::System.Collections.Generic;"); - } } } diff --git a/src/ProtoGen/IFieldSourceGenerator.cs b/src/ProtoGen/IFieldSourceGenerator.cs index 0753c5da..9c71a579 100644 --- a/src/ProtoGen/IFieldSourceGenerator.cs +++ b/src/ProtoGen/IFieldSourceGenerator.cs @@ -41,5 +41,9 @@ namespace Google.ProtocolBuffers.ProtoGen { void GenerateParsingCode(TextGenerator writer); void GenerateSerializationCode(TextGenerator writer); void GenerateSerializedSizeCode(TextGenerator writer); + + void WriteHash(TextGenerator writer); + void WriteEquals(TextGenerator writer); + void WriteToString(TextGenerator writer); } } diff --git a/src/ProtoGen/MessageFieldGenerator.cs b/src/ProtoGen/MessageFieldGenerator.cs index c2b5372e..d952984a 100644 --- a/src/ProtoGen/MessageFieldGenerator.cs +++ b/src/ProtoGen/MessageFieldGenerator.cs @@ -125,5 +125,18 @@ namespace Google.ProtocolBuffers.ProtoGen { MessageOrGroup, Number, PropertyName); writer.WriteLine("}"); } + + public override void WriteHash(TextGenerator writer) { + writer.WriteLine("if (has{0}) hash ^= {1}_.GetHashCode();", PropertyName, Name); + } + + public override void WriteEquals(TextGenerator writer) { + writer.WriteLine("if (has{0} != other.has{0} || (has{0} && !{1}_.Equals(other.{1}_))) return false;", PropertyName, Name); + } + + public override void WriteToString(TextGenerator writer) { + writer.WriteLine("PrintField(\"{2}\", has{0}, {1}_, writer);", PropertyName, Name, + Descriptor.FieldType == FieldType.Group ? Descriptor.MessageType.Name : Descriptor.Name); + } } } diff --git a/src/ProtoGen/MessageGenerator.cs b/src/ProtoGen/MessageGenerator.cs index 3488cdc9..43b8b7eb 100644 --- a/src/ProtoGen/MessageGenerator.cs +++ b/src/ProtoGen/MessageGenerator.cs @@ -32,6 +32,7 @@ // 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; @@ -69,12 +70,13 @@ namespace Google.ProtocolBuffers.ProtoGen { string identifier = GetUniqueFileScopeIdentifier(Descriptor); - // The descriptor for this type. - string access = Descriptor.File.CSharpOptions.NestClasses ? "private" : "internal"; - writer.WriteLine("{0} static pbd::MessageDescriptor internal__{1}__Descriptor;", access, identifier); - writer.WriteLine("{0} static pb::FieldAccess.FieldAccessorTable<{1}, {1}.Builder> internal__{2}__FieldAccessorTable;", - access, FullClassName, identifier); - + if (!UseLiteRuntime) { + // The descriptor for this type. + string access = Descriptor.File.CSharpOptions.NestClasses ? "private" : "internal"; + writer.WriteLine("{0} static pbd::MessageDescriptor internal__{1}__Descriptor;", access, identifier); + writer.WriteLine("{0} static pb::FieldAccess.FieldAccessorTable<{1}, {1}.Builder> internal__{2}__FieldAccessorTable;", + access, FullClassName, identifier); + } // Generate static members for all nested types. foreach (MessageDescriptor nestedMessage in Descriptor.NestedTypes) { new MessageGenerator(nestedMessage).GenerateStaticVariables(writer); @@ -84,21 +86,23 @@ namespace Google.ProtocolBuffers.ProtoGen { internal void GenerateStaticVariableInitializers(TextGenerator writer) { string identifier = GetUniqueFileScopeIdentifier(Descriptor); - writer.Write("internal__{0}__Descriptor = ", identifier); - if (Descriptor.ContainingType == null) { - writer.WriteLine("Descriptor.MessageTypes[{0}];", Descriptor.Index); - } else { - writer.WriteLine("internal__{0}__Descriptor.NestedTypes[{1}];", GetUniqueFileScopeIdentifier(Descriptor.ContainingType), Descriptor.Index); - } + if (!UseLiteRuntime) { + writer.Write("internal__{0}__Descriptor = ", identifier); + if (Descriptor.ContainingType == null) { + writer.WriteLine("Descriptor.MessageTypes[{0}];", Descriptor.Index); + } else { + writer.WriteLine("internal__{0}__Descriptor.NestedTypes[{1}];", GetUniqueFileScopeIdentifier(Descriptor.ContainingType), Descriptor.Index); + } - writer.WriteLine("internal__{0}__FieldAccessorTable = ", identifier); - writer.WriteLine(" new pb::FieldAccess.FieldAccessorTable<{1}, {1}.Builder>(internal__{0}__Descriptor,", - identifier, FullClassName); - writer.Print(" new string[] { "); - foreach (FieldDescriptor field in Descriptor.Fields) { - writer.Write("\"{0}\", ", field.CSharpOptions.PropertyName); + writer.WriteLine("internal__{0}__FieldAccessorTable = ", identifier); + writer.WriteLine(" new pb::FieldAccess.FieldAccessorTable<{1}, {1}.Builder>(internal__{0}__Descriptor,", + identifier, FullClassName); + writer.Print(" new string[] { "); + foreach (FieldDescriptor field in Descriptor.Fields) { + writer.Write("\"{0}\", ", field.CSharpOptions.PropertyName); + } + writer.WriteLine("});"); } - writer.WriteLine("});"); // Generate static member initializers for all nested types. foreach (MessageDescriptor nestedMessage in Descriptor.NestedTypes) { @@ -111,8 +115,10 @@ namespace Google.ProtocolBuffers.ProtoGen { } public void Generate(TextGenerator writer) { - writer.WriteLine("{0} sealed partial class {1} : pb::{2}Message<{1}, {1}.Builder> {{", - ClassAccessLevel, ClassName, Descriptor.Proto.ExtensionRangeCount > 0 ? "Extendable" : "Generated"); + 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(); // Must call BuildPartial() to make sure all lists are made read-only writer.WriteLine("private static readonly {0} defaultInstance = new Builder().BuildPartial();", ClassName); @@ -128,16 +134,18 @@ namespace Google.ProtocolBuffers.ProtoGen { writer.WriteLine(" get { return this; }"); writer.WriteLine("}"); writer.WriteLine(); - 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(); + 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); @@ -161,10 +169,13 @@ namespace Google.ProtocolBuffers.ProtoGen { writer.WriteLine(); } - if (Descriptor.File.Options.OptimizeFor == FileOptions.Types.OptimizeMode.SPEED) { + if (OptimizeSpeed) { GenerateIsInitialized(writer); GenerateMessageSerializationMethods(writer); } + if (UseLiteRuntime) { + GenerateLiteRuntimeMethods(writer); + } GenerateParseFromMethods(writer); GenerateBuilder(writer); @@ -184,6 +195,49 @@ namespace Google.ProtocolBuffers.ProtoGen { writer.WriteLine(); } + private void GenerateLiteRuntimeMethods(TextGenerator writer) { + + bool callbase = Descriptor.Proto.ExtensionRangeCount > 0; + writer.WriteLine("#region Lite runtime methods"); + writer.WriteLine("public override int GetHashCode() {"); + writer.Indent(); + writer.WriteLine("int hash = GetType().GetHashCode();"); + foreach (FieldDescriptor fieldDescriptor in Descriptor.Fields) { + SourceGenerators.CreateFieldGenerator(fieldDescriptor).WriteHash(writer); + } + if (callbase) writer.WriteLine("hash ^= base.GetHashCode();"); + writer.WriteLine("return hash;"); + writer.Outdent(); + writer.WriteLine("}"); + writer.WriteLine(); + + writer.WriteLine("public override bool Equals(object obj) {"); + writer.Indent(); + writer.WriteLine("{0} other = obj as {0};", ClassName); + writer.WriteLine("if (other == null) return false;"); + foreach (FieldDescriptor fieldDescriptor in Descriptor.Fields) { + SourceGenerators.CreateFieldGenerator(fieldDescriptor).WriteEquals(writer); + } + if (callbase) writer.WriteLine("if (!base.Equals(other)) return false;"); + writer.WriteLine("return true;"); + writer.Outdent(); + writer.WriteLine("}"); + writer.WriteLine(); + + writer.WriteLine("public override void PrintTo(global::System.IO.TextWriter writer) {"); + writer.Indent(); + List<FieldDescriptor> sorted = new List<FieldDescriptor>(Descriptor.Fields); + sorted.Sort(new Comparison<FieldDescriptor>(delegate(FieldDescriptor a, FieldDescriptor b) { return a.FieldNumber.CompareTo(b.FieldNumber); })); + foreach (FieldDescriptor fieldDescriptor in sorted) { + SourceGenerators.CreateFieldGenerator(fieldDescriptor).WriteToString(writer); + } + if (callbase) writer.WriteLine("base.PrintTo(writer);"); + writer.Outdent(); + writer.WriteLine("}"); + writer.WriteLine("#endregion"); + writer.WriteLine(); + } + private void GenerateMessageSerializationMethods(TextGenerator writer) { List<FieldDescriptor> sortedFields = new List<FieldDescriptor>(Descriptor.Fields); sortedFields.Sort((f1, f2) => f1.FieldNumber.CompareTo(f2.FieldNumber)); @@ -196,8 +250,8 @@ namespace Google.ProtocolBuffers.ProtoGen { // Make sure we've computed the serialized length, so that packed fields are generated correctly. writer.WriteLine("int size = SerializedSize;"); if (Descriptor.Proto.ExtensionRangeList.Count > 0) { - writer.WriteLine("pb::ExtendableMessage<{0}, {0}.Builder>.ExtensionWriter extensionWriter = CreateExtensionWriter(this);", - ClassName); + 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. @@ -213,10 +267,12 @@ namespace Google.ProtocolBuffers.ProtoGen { } } - if (Descriptor.Proto.Options.MessageSetWireFormat) { - writer.WriteLine("UnknownFields.WriteAsMessageSetTo(output);"); - } else { - writer.WriteLine("UnknownFields.WriteTo(output);"); + if (!UseLiteRuntime) { + if (Descriptor.Proto.Options.MessageSetWireFormat) { + writer.WriteLine("UnknownFields.WriteAsMessageSetTo(output);"); + } else { + writer.WriteLine("UnknownFields.WriteTo(output);"); + } } writer.Outdent(); @@ -238,10 +294,12 @@ namespace Google.ProtocolBuffers.ProtoGen { writer.WriteLine("size += ExtensionsSerializedSize;"); } - if (Descriptor.Options.MessageSetWireFormat) { - writer.WriteLine("size += UnknownFields.SerializedSizeAsMessageSet;"); - } else { - writer.WriteLine("size += UnknownFields.SerializedSize;"); + 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;"); @@ -345,14 +403,14 @@ namespace Google.ProtocolBuffers.ProtoGen { writer.WriteLine(" return (Builder) new Builder().MergeFrom(prototype);"); writer.WriteLine("}"); writer.WriteLine(); - writer.WriteLine("{0} sealed partial class Builder : pb::{2}Builder<{1}, Builder> {{", - ClassAccessLevel, ClassName, Descriptor.Proto.ExtensionRangeCount > 0 ? "Extendable" : "Generated"); + writer.WriteLine("{0} sealed partial class Builder : pb::{2}Builder{3}<{1}, Builder> {{", + ClassAccessLevel, ClassName, Descriptor.Proto.ExtensionRangeCount > 0 ? "Extendable" : "Generated", RuntimeSuffix); writer.Indent(); writer.WriteLine("protected override Builder ThisBuilder {"); writer.WriteLine(" get { return this; }"); writer.WriteLine("}"); GenerateCommonBuilderMethods(writer); - if (Descriptor.File.Options.OptimizeFor == FileOptions.Types.OptimizeMode.SPEED) { + if (OptimizeSpeed) { GenerateBuilderParsingMethods(writer); } foreach (FieldDescriptor field in Descriptor.Fields) { @@ -382,10 +440,12 @@ namespace Google.ProtocolBuffers.ProtoGen { writer.WriteLine(" return new Builder().MergeFrom(result);"); writer.WriteLine("}"); writer.WriteLine(); - writer.WriteLine("public override pbd::MessageDescriptor DescriptorForType {"); - writer.WriteLine(" get {{ return {0}.Descriptor; }}", FullClassName); - writer.WriteLine("}"); - writer.WriteLine(); + if (!UseLiteRuntime) { + writer.WriteLine("public override pbd::MessageDescriptor DescriptorForType {"); + writer.WriteLine(" get {{ return {0}.Descriptor; }}", FullClassName); + writer.WriteLine("}"); + writer.WriteLine(); + } writer.WriteLine("public override {0} DefaultInstanceForType {{", ClassName); writer.WriteLine(" get {{ return {0}.DefaultInstance; }}", FullClassName); writer.WriteLine("}"); @@ -406,8 +466,8 @@ namespace Google.ProtocolBuffers.ProtoGen { writer.WriteLine("}"); writer.WriteLine(); - if (Descriptor.File.Options.OptimizeFor == FileOptions.Types.OptimizeMode.SPEED) { - writer.WriteLine("public override Builder MergeFrom(pb::IMessage other) {"); + if (OptimizeSpeed) { + writer.WriteLine("public override Builder MergeFrom(pb::IMessage{0} other) {{", RuntimeSuffix); writer.WriteLine(" if (other is {0}) {{", ClassName); writer.WriteLine(" return MergeFrom(({0}) other);", ClassName); writer.WriteLine(" } else {"); @@ -428,7 +488,9 @@ namespace Google.ProtocolBuffers.ProtoGen { if (Descriptor.Proto.ExtensionRangeCount > 0) { writer.WriteLine(" this.MergeExtensionFields(other);"); } - writer.WriteLine("this.MergeUnknownFields(other.UnknownFields);"); + if (!UseLiteRuntime) { + writer.WriteLine("this.MergeUnknownFields(other.UnknownFields);"); + } writer.WriteLine("return this;"); writer.Outdent(); writer.WriteLine("}"); @@ -446,29 +508,37 @@ namespace Google.ProtocolBuffers.ProtoGen { writer.WriteLine(); writer.WriteLine("public override Builder MergeFrom(pb::CodedInputStream input, pb::ExtensionRegistry extensionRegistry) {"); writer.Indent(); - writer.WriteLine("pb::UnknownFieldSet.Builder unknownFields = null;"); + if (!UseLiteRuntime) { + writer.WriteLine("pb::UnknownFieldSet.Builder unknownFields = null;"); + } writer.WriteLine("while (true) {"); writer.Indent(); writer.WriteLine("uint tag = input.ReadTag();"); writer.WriteLine("switch (tag) {"); writer.Indent(); writer.WriteLine("case 0: {"); // 0 signals EOF / limit reached - writer.WriteLine(" if (unknownFields != null) {"); - writer.WriteLine(" this.UnknownFields = unknownFields.Build();"); - writer.WriteLine(" }"); + if (!UseLiteRuntime) { + writer.WriteLine(" if (unknownFields != null) {"); + writer.WriteLine(" this.UnknownFields = unknownFields.Build();"); + writer.WriteLine(" }"); + } writer.WriteLine(" return this;"); writer.WriteLine("}"); writer.WriteLine("default: {"); writer.WriteLine(" if (pb::WireFormat.IsEndGroupTag(tag)) {"); - writer.WriteLine(" if (unknownFields != null) {"); - writer.WriteLine(" this.UnknownFields = unknownFields.Build();"); - writer.WriteLine(" }"); + 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(" }"); - 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, unknownFields, extensionRegistry, tag);"); + 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);", UseLiteRuntime ? "" : "unknownFields, "); writer.WriteLine(" break;"); writer.WriteLine("}"); foreach (FieldDescriptor field in sortedFields) { diff --git a/src/ProtoGen/PrimitiveFieldGenerator.cs b/src/ProtoGen/PrimitiveFieldGenerator.cs index ce3fd238..dbc203d0 100644 --- a/src/ProtoGen/PrimitiveFieldGenerator.cs +++ b/src/ProtoGen/PrimitiveFieldGenerator.cs @@ -103,5 +103,17 @@ namespace Google.ProtocolBuffers.ProtoGen { CapitalizedTypeName, Number, PropertyName); writer.WriteLine("}"); } + + public override void WriteHash(TextGenerator writer) { + writer.WriteLine("if (has{0}) hash ^= {1}_.GetHashCode();", PropertyName, Name); + } + + public override void WriteEquals(TextGenerator writer) { + writer.WriteLine("if (has{0} != other.has{0} || (has{0} && !{1}_.Equals(other.{1}_))) return false;", PropertyName, Name); + } + + public override void WriteToString(TextGenerator writer) { + writer.WriteLine("PrintField(\"{0}\", has{1}, {2}_, writer);", Descriptor.Name, PropertyName, Name); + } } } diff --git a/src/ProtoGen/RepeatedEnumFieldGenerator.cs b/src/ProtoGen/RepeatedEnumFieldGenerator.cs index b2f2aa53..c500d38b 100644 --- a/src/ProtoGen/RepeatedEnumFieldGenerator.cs +++ b/src/ProtoGen/RepeatedEnumFieldGenerator.cs @@ -43,7 +43,7 @@ namespace Google.ProtocolBuffers.ProtoGen { } public void GenerateMembers(TextGenerator writer) { - if (Descriptor.IsPacked && Descriptor.File.Options.OptimizeFor == FileOptions.Types.OptimizeMode.SPEED) { + if (Descriptor.IsPacked && OptimizeSpeed) { writer.WriteLine("private int {0}MemoizedSerializedSize;", Name); } writer.WriteLine("private pbc::PopsicleList<{0}> {1}_ = new pbc::PopsicleList<{0}>();", TypeName, Name); @@ -114,10 +114,12 @@ namespace Google.ProtocolBuffers.ProtoGen { // TODO(jonskeet): Make a more efficient way of doing this writer.WriteLine("int rawValue = input.ReadEnum();"); writer.WriteLine("if (!global::System.Enum.IsDefined(typeof({0}), rawValue)) {{", TypeName); - writer.WriteLine(" if (unknownFields == null) {"); // First unknown field - create builder now - writer.WriteLine(" unknownFields = pb::UnknownFieldSet.CreateBuilder(this.UnknownFields);"); - writer.WriteLine(" }"); - writer.WriteLine(" unknownFields.MergeVarintField({0}, (ulong) rawValue);", Number); + 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(" unknownFields.MergeVarintField({0}, (ulong) rawValue);", Number); + } writer.WriteLine("} else {"); writer.WriteLine(" Add{0}(({1}) rawValue);", PropertyName, TypeName); writer.WriteLine("}"); @@ -173,5 +175,20 @@ namespace Google.ProtocolBuffers.ProtoGen { writer.Outdent(); writer.WriteLine("}"); } + + public override void WriteHash(TextGenerator writer) { + writer.WriteLine("foreach({0} i in {1}_)", TypeName, Name); + writer.WriteLine(" hash ^= i.GetHashCode();"); + } + + public override void WriteEquals(TextGenerator writer) { + writer.WriteLine("if({0}_.Count != other.{0}_.Count) return false;", Name); + writer.WriteLine("for(int ix=0; ix < {0}_.Count; ix++)", Name); + writer.WriteLine(" if(!{0}_[ix].Equals(other.{0}_[ix])) return false;", Name); + } + + public override void WriteToString(TextGenerator writer) { + writer.WriteLine("PrintField(\"{0}\", {1}_, writer);", Descriptor.Name, Name); + } } } diff --git a/src/ProtoGen/RepeatedMessageFieldGenerator.cs b/src/ProtoGen/RepeatedMessageFieldGenerator.cs index 3eac8090..4461190f 100644 --- a/src/ProtoGen/RepeatedMessageFieldGenerator.cs +++ b/src/ProtoGen/RepeatedMessageFieldGenerator.cs @@ -132,5 +132,22 @@ namespace Google.ProtocolBuffers.ProtoGen { writer.WriteLine(" size += pb::CodedOutputStream.Compute{0}Size({1}, element);", MessageOrGroup, Number); writer.WriteLine("}"); } + + public override void WriteHash(TextGenerator writer) { + writer.WriteLine("foreach({0} i in {1}_)", TypeName, Name); + writer.WriteLine(" hash ^= i.GetHashCode();"); + } + + public override void WriteEquals(TextGenerator writer) { + writer.WriteLine("if({0}_.Count != other.{0}_.Count) return false;", Name); + writer.WriteLine("for(int ix=0; ix < {0}_.Count; ix++)", Name); + writer.WriteLine(" if(!{0}_[ix].Equals(other.{0}_[ix])) return false;", Name); + } + + public override void WriteToString(TextGenerator writer) { + writer.WriteLine("PrintField(\"{0}\", {1}_, writer);", + Descriptor.FieldType == FieldType.Group ? Descriptor.MessageType.Name : Descriptor.Name, Name); + } + } } diff --git a/src/ProtoGen/RepeatedPrimitiveFieldGenerator.cs b/src/ProtoGen/RepeatedPrimitiveFieldGenerator.cs index af49b611..d670c4ce 100644 --- a/src/ProtoGen/RepeatedPrimitiveFieldGenerator.cs +++ b/src/ProtoGen/RepeatedPrimitiveFieldGenerator.cs @@ -43,7 +43,7 @@ namespace Google.ProtocolBuffers.ProtoGen { } public void GenerateMembers(TextGenerator writer) { - if (Descriptor.IsPacked && Descriptor.File.Options.OptimizeFor == FileOptions.Types.OptimizeMode.SPEED) { + if (Descriptor.IsPacked && OptimizeSpeed) { writer.WriteLine("private int {0}MemoizedSerializedSize;", Name); } writer.WriteLine("private pbc::PopsicleList<{0}> {1}_ = new pbc::PopsicleList<{0}>();", TypeName, Name); @@ -168,5 +168,20 @@ namespace Google.ProtocolBuffers.ProtoGen { writer.Outdent(); writer.WriteLine("}"); } + + public override void WriteHash(TextGenerator writer) { + writer.WriteLine("foreach({0} i in {1}_)", TypeName, Name); + writer.WriteLine(" hash ^= i.GetHashCode();"); + } + + public override void WriteEquals(TextGenerator writer) { + writer.WriteLine("if({0}_.Count != other.{0}_.Count) return false;", Name); + writer.WriteLine("for(int ix=0; ix < {0}_.Count; ix++)", Name); + writer.WriteLine(" if(!{0}_[ix].Equals(other.{0}_[ix])) return false;", Name); + } + + public override void WriteToString(TextGenerator writer) { + writer.WriteLine("PrintField(\"{0}\", {1}_, writer);", Descriptor.Name, Name); + } } } diff --git a/src/ProtoGen/SourceGeneratorBase.cs b/src/ProtoGen/SourceGeneratorBase.cs index 02f84577..a7dc2f93 100644 --- a/src/ProtoGen/SourceGeneratorBase.cs +++ b/src/ProtoGen/SourceGeneratorBase.cs @@ -40,8 +40,20 @@ namespace Google.ProtocolBuffers.ProtoGen { private readonly T descriptor; + protected readonly bool OptimizeSpeed; + protected readonly bool OptimizeSize; + protected readonly bool UseLiteRuntime; + protected readonly string RuntimeSuffix; + protected SourceGeneratorBase(T descriptor) { this.descriptor = descriptor; + + OptimizeSize = descriptor.File.Options.OptimizeFor == Google.ProtocolBuffers.DescriptorProtos.FileOptions.Types.OptimizeMode.CODE_SIZE; + OptimizeSpeed = descriptor.File.Options.OptimizeFor == Google.ProtocolBuffers.DescriptorProtos.FileOptions.Types.OptimizeMode.SPEED; + UseLiteRuntime = descriptor.File.Options.OptimizeFor == Google.ProtocolBuffers.DescriptorProtos.FileOptions.Types.OptimizeMode.LITE_RUNTIME; + //Lite runtime uses OptimizeSpeed code branches + OptimizeSpeed |= UseLiteRuntime; + RuntimeSuffix = UseLiteRuntime ? "Lite" : ""; } protected T Descriptor { diff --git a/src/ProtoGen/UmbrellaClassGenerator.cs b/src/ProtoGen/UmbrellaClassGenerator.cs index cdc275c6..e1bbee5d 100644 --- a/src/ProtoGen/UmbrellaClassGenerator.cs +++ b/src/ProtoGen/UmbrellaClassGenerator.cs @@ -74,10 +74,6 @@ namespace Google.ProtocolBuffers.ProtoGen { return false; } - public string UmbrellaClassName { - get { throw new NotImplementedException(); } - } - public void Generate(TextGenerator writer) { WriteIntroduction(writer); WriteExtensionRegistration(writer); @@ -87,7 +83,11 @@ namespace Google.ProtocolBuffers.ProtoGen { new MessageGenerator(message).GenerateStaticVariables(writer); } writer.WriteLine("#endregion"); - WriteDescriptor(writer); + if (!UseLiteRuntime) { + WriteDescriptor(writer); + } else { + WriteLiteExtensions(writer); + } // The class declaration either gets closed before or after the children are written. if (!Descriptor.CSharpOptions.NestClasses) { writer.Outdent(); @@ -113,9 +113,12 @@ namespace Google.ProtocolBuffers.ProtoGen { } private void WriteIntroduction(TextGenerator writer) { - writer.WriteLine("// Generated by the protocol buffer compiler. DO NOT EDIT!"); + writer.WriteLine("// Generated by {0}. DO NOT EDIT!", this.GetType().Assembly.FullName); writer.WriteLine(); - Helpers.WriteNamespaces(writer); + writer.WriteLine("using pb = global::Google.ProtocolBuffers;"); + writer.WriteLine("using pbc = global::Google.ProtocolBuffers.Collections;"); + writer.WriteLine("using pbd = global::Google.ProtocolBuffers.Descriptors;"); + writer.WriteLine("using scg = global::System.Collections.Generic;"); if (Descriptor.CSharpOptions.Namespace != "") { writer.WriteLine("namespace {0} {{", Descriptor.CSharpOptions.Namespace); @@ -215,5 +218,24 @@ namespace Google.ProtocolBuffers.ProtoGen { writer.WriteLine("#endregion"); writer.WriteLine(); } + + private void WriteLiteExtensions(TextGenerator writer) { + writer.WriteLine("#region Extensions"); + writer.WriteLine("internal static readonly object Descriptor;"); + writer.WriteLine("static {0}() {{", Descriptor.CSharpOptions.UmbrellaClassname); + writer.Indent(); + writer.WriteLine("Descriptor = null;"); + + foreach (MessageDescriptor message in Descriptor.MessageTypes) { + new MessageGenerator(message).GenerateStaticVariableInitializers(writer); + } + foreach (FieldDescriptor extension in Descriptor.Extensions) { + new ExtensionGenerator(extension).GenerateStaticVariableInitializers(writer); + } + writer.Outdent(); + writer.WriteLine("}"); + writer.WriteLine("#endregion"); + writer.WriteLine(); + } } } |