aboutsummaryrefslogtreecommitdiff
path: root/src/ProtoGen
diff options
context:
space:
mode:
authorJon Skeet <skeet@pobox.com>2010-12-12 12:37:30 +0000
committerJon Skeet <skeet@pobox.com>2010-12-12 12:37:30 +0000
commit1738462b7fbaf806a3bc28b52b61a037b45a73f4 (patch)
treec29623a454f41741a1cd0f265709cd4cd92647a0 /src/ProtoGen
parent0c58d060f7e919439210fff5ee107e023b1c8199 (diff)
parent00ca60805301f14ff4abc70cef5cd6df0b3f8b67 (diff)
downloadprotobuf-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.cs24
-rw-r--r--src/ProtoGen/ExtensionGenerator.cs57
-rw-r--r--src/ProtoGen/FieldGeneratorBase.cs34
-rw-r--r--src/ProtoGen/Helpers.cs6
-rw-r--r--src/ProtoGen/IFieldSourceGenerator.cs4
-rw-r--r--src/ProtoGen/MessageFieldGenerator.cs13
-rw-r--r--src/ProtoGen/MessageGenerator.cs196
-rw-r--r--src/ProtoGen/PrimitiveFieldGenerator.cs12
-rw-r--r--src/ProtoGen/RepeatedEnumFieldGenerator.cs27
-rw-r--r--src/ProtoGen/RepeatedMessageFieldGenerator.cs17
-rw-r--r--src/ProtoGen/RepeatedPrimitiveFieldGenerator.cs17
-rw-r--r--src/ProtoGen/SourceGeneratorBase.cs12
-rw-r--r--src/ProtoGen/UmbrellaClassGenerator.cs36
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();
+ }
}
}