Commit 804b6d84 authored by csharptest's avatar csharptest

Implementation work for Lite runtime and generator

parent 64bfac28
...@@ -38,11 +38,5 @@ namespace Google.ProtocolBuffers.ProtoGen { ...@@ -38,11 +38,5 @@ namespace Google.ProtocolBuffers.ProtoGen {
/// Helpers to resolve class names etc. /// Helpers to resolve class names etc.
/// </summary> /// </summary>
internal static class Helpers { 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;");
}
} }
} }
...@@ -69,12 +69,13 @@ namespace Google.ProtocolBuffers.ProtoGen { ...@@ -69,12 +69,13 @@ namespace Google.ProtocolBuffers.ProtoGen {
string identifier = GetUniqueFileScopeIdentifier(Descriptor); string identifier = GetUniqueFileScopeIdentifier(Descriptor);
// The descriptor for this type. if (!UseLiteRuntime) {
string access = Descriptor.File.CSharpOptions.NestClasses ? "private" : "internal"; // The descriptor for this type.
writer.WriteLine("{0} static pbd::MessageDescriptor internal__{1}__Descriptor;", access, identifier); string access = Descriptor.File.CSharpOptions.NestClasses ? "private" : "internal";
writer.WriteLine("{0} static pb::FieldAccess.FieldAccessorTable<{1}, {1}.Builder> internal__{2}__FieldAccessorTable;", writer.WriteLine("{0} static pbd::MessageDescriptor internal__{1}__Descriptor;", access, identifier);
access, FullClassName, identifier); writer.WriteLine("{0} static pb::FieldAccess.FieldAccessorTable<{1}, {1}.Builder> internal__{2}__FieldAccessorTable;",
access, FullClassName, identifier);
}
// Generate static members for all nested types. // Generate static members for all nested types.
foreach (MessageDescriptor nestedMessage in Descriptor.NestedTypes) { foreach (MessageDescriptor nestedMessage in Descriptor.NestedTypes) {
new MessageGenerator(nestedMessage).GenerateStaticVariables(writer); new MessageGenerator(nestedMessage).GenerateStaticVariables(writer);
...@@ -84,21 +85,23 @@ namespace Google.ProtocolBuffers.ProtoGen { ...@@ -84,21 +85,23 @@ namespace Google.ProtocolBuffers.ProtoGen {
internal void GenerateStaticVariableInitializers(TextGenerator writer) { internal void GenerateStaticVariableInitializers(TextGenerator writer) {
string identifier = GetUniqueFileScopeIdentifier(Descriptor); string identifier = GetUniqueFileScopeIdentifier(Descriptor);
writer.Write("internal__{0}__Descriptor = ", identifier); if (!UseLiteRuntime) {
if (Descriptor.ContainingType == null) { writer.Write("internal__{0}__Descriptor = ", identifier);
writer.WriteLine("Descriptor.MessageTypes[{0}];", Descriptor.Index); if (Descriptor.ContainingType == null) {
} else { writer.WriteLine("Descriptor.MessageTypes[{0}];", Descriptor.Index);
writer.WriteLine("internal__{0}__Descriptor.NestedTypes[{1}];", GetUniqueFileScopeIdentifier(Descriptor.ContainingType), Descriptor.Index); } else {
} writer.WriteLine("internal__{0}__Descriptor.NestedTypes[{1}];", GetUniqueFileScopeIdentifier(Descriptor.ContainingType), Descriptor.Index);
}
writer.WriteLine("internal__{0}__FieldAccessorTable = ", identifier); writer.WriteLine("internal__{0}__FieldAccessorTable = ", identifier);
writer.WriteLine(" new pb::FieldAccess.FieldAccessorTable<{1}, {1}.Builder>(internal__{0}__Descriptor,", writer.WriteLine(" new pb::FieldAccess.FieldAccessorTable<{1}, {1}.Builder>(internal__{0}__Descriptor,",
identifier, FullClassName); identifier, FullClassName);
writer.Print(" new string[] { "); writer.Print(" new string[] { ");
foreach (FieldDescriptor field in Descriptor.Fields) { foreach (FieldDescriptor field in Descriptor.Fields) {
writer.Write("\"{0}\", ", field.CSharpOptions.PropertyName); writer.Write("\"{0}\", ", field.CSharpOptions.PropertyName);
}
writer.WriteLine("});");
} }
writer.WriteLine("});");
// Generate static member initializers for all nested types. // Generate static member initializers for all nested types.
foreach (MessageDescriptor nestedMessage in Descriptor.NestedTypes) { foreach (MessageDescriptor nestedMessage in Descriptor.NestedTypes) {
...@@ -111,8 +114,10 @@ namespace Google.ProtocolBuffers.ProtoGen { ...@@ -111,8 +114,10 @@ namespace Google.ProtocolBuffers.ProtoGen {
} }
public void Generate(TextGenerator writer) { public void Generate(TextGenerator writer) {
writer.WriteLine("{0} sealed partial class {1} : pb::{2}Message<{1}, {1}.Builder> {{", writer.WriteLine("{0} sealed partial class {1} : pb::{2}Message{3}<{1}, {1}.Builder> {{",
ClassAccessLevel, ClassName, Descriptor.Proto.ExtensionRangeCount > 0 ? "Extendable" : "Generated"); ClassAccessLevel, ClassName,
Descriptor.Proto.ExtensionRangeCount > 0 ? "Extendable" : "Generated",
UseLiteRuntime ? "Lite" : "");
writer.Indent(); writer.Indent();
// Must call BuildPartial() to make sure all lists are made read-only // Must call BuildPartial() to make sure all lists are made read-only
writer.WriteLine("private static readonly {0} defaultInstance = new Builder().BuildPartial();", ClassName); writer.WriteLine("private static readonly {0} defaultInstance = new Builder().BuildPartial();", ClassName);
...@@ -128,16 +133,18 @@ namespace Google.ProtocolBuffers.ProtoGen { ...@@ -128,16 +133,18 @@ namespace Google.ProtocolBuffers.ProtoGen {
writer.WriteLine(" get { return this; }"); writer.WriteLine(" get { return this; }");
writer.WriteLine("}"); writer.WriteLine("}");
writer.WriteLine(); writer.WriteLine();
writer.WriteLine("public static pbd::MessageDescriptor Descriptor {"); if (!UseLiteRuntime) {
writer.WriteLine(" get {{ return {0}.internal__{1}__Descriptor; }}", DescriptorUtil.GetFullUmbrellaClassName(Descriptor), writer.WriteLine("public static pbd::MessageDescriptor Descriptor {");
GetUniqueFileScopeIdentifier(Descriptor)); writer.WriteLine(" get {{ return {0}.internal__{1}__Descriptor; }}", DescriptorUtil.GetFullUmbrellaClassName(Descriptor),
writer.WriteLine("}"); GetUniqueFileScopeIdentifier(Descriptor));
writer.WriteLine(); writer.WriteLine("}");
writer.WriteLine("protected override pb::FieldAccess.FieldAccessorTable<{0}, {0}.Builder> InternalFieldAccessors {{", ClassName); writer.WriteLine();
writer.WriteLine(" get {{ return {0}.internal__{1}__FieldAccessorTable; }}", DescriptorUtil.GetFullUmbrellaClassName(Descriptor), writer.WriteLine("protected override pb::FieldAccess.FieldAccessorTable<{0}, {0}.Builder> InternalFieldAccessors {{", ClassName);
GetUniqueFileScopeIdentifier(Descriptor)); writer.WriteLine(" get {{ return {0}.internal__{1}__FieldAccessorTable; }}", DescriptorUtil.GetFullUmbrellaClassName(Descriptor),
writer.WriteLine("}"); GetUniqueFileScopeIdentifier(Descriptor));
writer.WriteLine(); writer.WriteLine("}");
writer.WriteLine();
}
// Extensions don't need to go in an extra nested type // Extensions don't need to go in an extra nested type
WriteChildren(writer, null, Descriptor.Extensions); WriteChildren(writer, null, Descriptor.Extensions);
......
...@@ -40,8 +40,16 @@ namespace Google.ProtocolBuffers.ProtoGen { ...@@ -40,8 +40,16 @@ namespace Google.ProtocolBuffers.ProtoGen {
private readonly T descriptor; private readonly T descriptor;
protected readonly bool OptimizeSpeed;
protected readonly bool OptimizeSize;
protected readonly bool UseLiteRuntime;
protected SourceGeneratorBase(T descriptor) { protected SourceGeneratorBase(T descriptor) {
this.descriptor = 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;
} }
protected T Descriptor { protected T Descriptor {
......
...@@ -83,7 +83,11 @@ namespace Google.ProtocolBuffers.ProtoGen { ...@@ -83,7 +83,11 @@ namespace Google.ProtocolBuffers.ProtoGen {
new MessageGenerator(message).GenerateStaticVariables(writer); new MessageGenerator(message).GenerateStaticVariables(writer);
} }
writer.WriteLine("#endregion"); 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. // The class declaration either gets closed before or after the children are written.
if (!Descriptor.CSharpOptions.NestClasses) { if (!Descriptor.CSharpOptions.NestClasses) {
writer.Outdent(); writer.Outdent();
...@@ -111,7 +115,12 @@ namespace Google.ProtocolBuffers.ProtoGen { ...@@ -111,7 +115,12 @@ namespace Google.ProtocolBuffers.ProtoGen {
private void WriteIntroduction(TextGenerator writer) { private void WriteIntroduction(TextGenerator writer) {
writer.WriteLine("// Generated by the protocol buffer compiler. DO NOT EDIT!"); writer.WriteLine("// Generated by the protocol buffer compiler. DO NOT EDIT!");
writer.WriteLine(); writer.WriteLine();
Helpers.WriteNamespaces(writer); writer.WriteLine("using pb = global::Google.ProtocolBuffers;");
if (!UseLiteRuntime) {
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 != "") { if (Descriptor.CSharpOptions.Namespace != "") {
writer.WriteLine("namespace {0} {{", Descriptor.CSharpOptions.Namespace); writer.WriteLine("namespace {0} {{", Descriptor.CSharpOptions.Namespace);
...@@ -211,5 +220,23 @@ namespace Google.ProtocolBuffers.ProtoGen { ...@@ -211,5 +220,23 @@ namespace Google.ProtocolBuffers.ProtoGen {
writer.WriteLine("#endregion"); writer.WriteLine("#endregion");
writer.WriteLine(); writer.WriteLine();
} }
private void WriteLiteExtensions(TextGenerator writer) {
writer.WriteLine("#region Extensions");
writer.WriteLine("static {0}() {{", Descriptor.CSharpOptions.UmbrellaClassname);
writer.Indent();
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();
}
} }
} }
...@@ -36,9 +36,7 @@ using System; ...@@ -36,9 +36,7 @@ using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.IO; using System.IO;
using System.Text; using System.Text;
#if !LITE
using Google.ProtocolBuffers.Descriptors; using Google.ProtocolBuffers.Descriptors;
#endif
namespace Google.ProtocolBuffers { namespace Google.ProtocolBuffers {
...@@ -363,7 +361,7 @@ namespace Google.ProtocolBuffers { ...@@ -363,7 +361,7 @@ namespace Google.ProtocolBuffers {
public long ReadSInt64() { public long ReadSInt64() {
return DecodeZigZag64(ReadRawVarint64()); return DecodeZigZag64(ReadRawVarint64());
} }
#if !LITE
/// <summary> /// <summary>
/// Reads a field of any primitive type. Enums, groups and embedded /// Reads a field of any primitive type. Enums, groups and embedded
/// messages are not handled by this method. /// messages are not handled by this method.
...@@ -397,7 +395,6 @@ namespace Google.ProtocolBuffers { ...@@ -397,7 +395,6 @@ namespace Google.ProtocolBuffers {
throw new ArgumentOutOfRangeException("Invalid field type " + fieldType); throw new ArgumentOutOfRangeException("Invalid field type " + fieldType);
} }
} }
#endif
#endregion #endregion
#region Underlying reading primitives #region Underlying reading primitives
......
...@@ -35,9 +35,8 @@ ...@@ -35,9 +35,8 @@
using System; using System;
using System.IO; using System.IO;
using System.Text; using System.Text;
#if !LITE
using Google.ProtocolBuffers.Descriptors; using Google.ProtocolBuffers.Descriptors;
#endif
namespace Google.ProtocolBuffers { namespace Google.ProtocolBuffers {
/// <summary> /// <summary>
...@@ -279,7 +278,6 @@ namespace Google.ProtocolBuffers { ...@@ -279,7 +278,6 @@ namespace Google.ProtocolBuffers {
WriteTag(WireFormat.MessageSetField.Item, WireFormat.WireType.EndGroup); WriteTag(WireFormat.MessageSetField.Item, WireFormat.WireType.EndGroup);
} }
#if !LITE
public void WriteField(FieldType fieldType, int fieldNumber, object value) { public void WriteField(FieldType fieldType, int fieldNumber, object value) {
switch (fieldType) { switch (fieldType) {
case FieldType.Double: WriteDouble(fieldNumber, (double)value); break; case FieldType.Double: WriteDouble(fieldNumber, (double)value); break;
...@@ -291,15 +289,15 @@ namespace Google.ProtocolBuffers { ...@@ -291,15 +289,15 @@ namespace Google.ProtocolBuffers {
case FieldType.Fixed32: WriteFixed32(fieldNumber, (uint)value); break; case FieldType.Fixed32: WriteFixed32(fieldNumber, (uint)value); break;
case FieldType.Bool: WriteBool(fieldNumber, (bool)value); break; case FieldType.Bool: WriteBool(fieldNumber, (bool)value); break;
case FieldType.String: WriteString(fieldNumber, (string)value); break; case FieldType.String: WriteString(fieldNumber, (string)value); break;
case FieldType.Group: WriteGroup(fieldNumber, (IMessage)value); break; case FieldType.Group: WriteGroup(fieldNumber, (IMessageLite)value); break;
case FieldType.Message: WriteMessage(fieldNumber, (IMessage)value); break; case FieldType.Message: WriteMessage(fieldNumber, (IMessageLite)value); break;
case FieldType.Bytes: WriteBytes(fieldNumber, (ByteString)value); break; case FieldType.Bytes: WriteBytes(fieldNumber, (ByteString)value); break;
case FieldType.UInt32: WriteUInt32(fieldNumber, (uint)value); break; case FieldType.UInt32: WriteUInt32(fieldNumber, (uint)value); break;
case FieldType.SFixed32: WriteSFixed32(fieldNumber, (int)value); break; case FieldType.SFixed32: WriteSFixed32(fieldNumber, (int)value); break;
case FieldType.SFixed64: WriteSFixed64(fieldNumber, (long)value); break; case FieldType.SFixed64: WriteSFixed64(fieldNumber, (long)value); break;
case FieldType.SInt32: WriteSInt32(fieldNumber, (int)value); break; case FieldType.SInt32: WriteSInt32(fieldNumber, (int)value); break;
case FieldType.SInt64: WriteSInt64(fieldNumber, (long)value); break; case FieldType.SInt64: WriteSInt64(fieldNumber, (long)value); break;
case FieldType.Enum: WriteEnum(fieldNumber, ((EnumValueDescriptor)value).Number); case FieldType.Enum: WriteEnum(fieldNumber, ((IEnumLite)value).Number);
break; break;
} }
} }
...@@ -315,19 +313,18 @@ namespace Google.ProtocolBuffers { ...@@ -315,19 +313,18 @@ namespace Google.ProtocolBuffers {
case FieldType.Fixed32: WriteFixed32NoTag((uint)value); break; case FieldType.Fixed32: WriteFixed32NoTag((uint)value); break;
case FieldType.Bool: WriteBoolNoTag((bool)value); break; case FieldType.Bool: WriteBoolNoTag((bool)value); break;
case FieldType.String: WriteStringNoTag((string)value); break; case FieldType.String: WriteStringNoTag((string)value); break;
case FieldType.Group: WriteGroupNoTag((IMessage)value); break; case FieldType.Group: WriteGroupNoTag((IMessageLite)value); break;
case FieldType.Message: WriteMessageNoTag((IMessage)value); break; case FieldType.Message: WriteMessageNoTag((IMessageLite)value); break;
case FieldType.Bytes: WriteBytesNoTag((ByteString)value); break; case FieldType.Bytes: WriteBytesNoTag((ByteString)value); break;
case FieldType.UInt32: WriteUInt32NoTag((uint)value); break; case FieldType.UInt32: WriteUInt32NoTag((uint)value); break;
case FieldType.SFixed32: WriteSFixed32NoTag((int)value); break; case FieldType.SFixed32: WriteSFixed32NoTag((int)value); break;
case FieldType.SFixed64: WriteSFixed64NoTag((long)value); break; case FieldType.SFixed64: WriteSFixed64NoTag((long)value); break;
case FieldType.SInt32: WriteSInt32NoTag((int)value); break; case FieldType.SInt32: WriteSInt32NoTag((int)value); break;
case FieldType.SInt64: WriteSInt64NoTag((long)value); break; case FieldType.SInt64: WriteSInt64NoTag((long)value); break;
case FieldType.Enum: WriteEnumNoTag(((EnumValueDescriptor)value).Number); case FieldType.Enum: WriteEnumNoTag(((IEnumLite)value).Number);
break; break;
} }
} }
#endif
#endregion #endregion
#region Writing of values without tags #region Writing of values without tags
...@@ -995,7 +992,6 @@ namespace Google.ProtocolBuffers { ...@@ -995,7 +992,6 @@ namespace Google.ProtocolBuffers {
return 10; return 10;
} }
#if !LITE
/// <summary> /// <summary>
/// Compute the number of bytes that would be needed to encode a /// Compute the number of bytes that would be needed to encode a
/// field of arbitrary type, including the tag, to the stream. /// field of arbitrary type, including the tag, to the stream.
...@@ -1011,15 +1007,15 @@ namespace Google.ProtocolBuffers { ...@@ -1011,15 +1007,15 @@ namespace Google.ProtocolBuffers {
case FieldType.Fixed32: return ComputeFixed32Size(fieldNumber, (uint)value); case FieldType.Fixed32: return ComputeFixed32Size(fieldNumber, (uint)value);
case FieldType.Bool: return ComputeBoolSize(fieldNumber, (bool)value); case FieldType.Bool: return ComputeBoolSize(fieldNumber, (bool)value);
case FieldType.String: return ComputeStringSize(fieldNumber, (string)value); case FieldType.String: return ComputeStringSize(fieldNumber, (string)value);
case FieldType.Group: return ComputeGroupSize(fieldNumber, (IMessage)value); case FieldType.Group: return ComputeGroupSize(fieldNumber, (IMessageLite)value);
case FieldType.Message: return ComputeMessageSize(fieldNumber, (IMessage)value); case FieldType.Message: return ComputeMessageSize(fieldNumber, (IMessageLite)value);
case FieldType.Bytes: return ComputeBytesSize(fieldNumber, (ByteString)value); case FieldType.Bytes: return ComputeBytesSize(fieldNumber, (ByteString)value);
case FieldType.UInt32: return ComputeUInt32Size(fieldNumber, (uint)value); case FieldType.UInt32: return ComputeUInt32Size(fieldNumber, (uint)value);
case FieldType.SFixed32: return ComputeSFixed32Size(fieldNumber, (int)value); case FieldType.SFixed32: return ComputeSFixed32Size(fieldNumber, (int)value);
case FieldType.SFixed64: return ComputeSFixed64Size(fieldNumber, (long)value); case FieldType.SFixed64: return ComputeSFixed64Size(fieldNumber, (long)value);
case FieldType.SInt32: return ComputeSInt32Size(fieldNumber, (int)value); case FieldType.SInt32: return ComputeSInt32Size(fieldNumber, (int)value);
case FieldType.SInt64: return ComputeSInt64Size(fieldNumber, (long)value); case FieldType.SInt64: return ComputeSInt64Size(fieldNumber, (long)value);
case FieldType.Enum: return ComputeEnumSize(fieldNumber, ((EnumValueDescriptor)value).Number); case FieldType.Enum: return ComputeEnumSize(fieldNumber, ((IEnumLite)value).Number);
default: default:
throw new ArgumentOutOfRangeException("Invalid field type " + fieldType); throw new ArgumentOutOfRangeException("Invalid field type " + fieldType);
} }
...@@ -1040,20 +1036,19 @@ namespace Google.ProtocolBuffers { ...@@ -1040,20 +1036,19 @@ namespace Google.ProtocolBuffers {
case FieldType.Fixed32: return ComputeFixed32SizeNoTag((uint)value); case FieldType.Fixed32: return ComputeFixed32SizeNoTag((uint)value);
case FieldType.Bool: return ComputeBoolSizeNoTag((bool)value); case FieldType.Bool: return ComputeBoolSizeNoTag((bool)value);
case FieldType.String: return ComputeStringSizeNoTag((string)value); case FieldType.String: return ComputeStringSizeNoTag((string)value);
case FieldType.Group: return ComputeGroupSizeNoTag((IMessage)value); case FieldType.Group: return ComputeGroupSizeNoTag((IMessageLite)value);
case FieldType.Message: return ComputeMessageSizeNoTag((IMessage)value); case FieldType.Message: return ComputeMessageSizeNoTag((IMessageLite)value);
case FieldType.Bytes: return ComputeBytesSizeNoTag((ByteString)value); case FieldType.Bytes: return ComputeBytesSizeNoTag((ByteString)value);
case FieldType.UInt32: return ComputeUInt32SizeNoTag((uint)value); case FieldType.UInt32: return ComputeUInt32SizeNoTag((uint)value);
case FieldType.SFixed32: return ComputeSFixed32SizeNoTag((int)value); case FieldType.SFixed32: return ComputeSFixed32SizeNoTag((int)value);
case FieldType.SFixed64: return ComputeSFixed64SizeNoTag((long)value); case FieldType.SFixed64: return ComputeSFixed64SizeNoTag((long)value);
case FieldType.SInt32: return ComputeSInt32SizeNoTag((int)value); case FieldType.SInt32: return ComputeSInt32SizeNoTag((int)value);
case FieldType.SInt64: return ComputeSInt64SizeNoTag((long)value); case FieldType.SInt64: return ComputeSInt64SizeNoTag((long)value);
case FieldType.Enum: return ComputeEnumSizeNoTag(((EnumValueDescriptor)value).Number); case FieldType.Enum: return ComputeEnumSizeNoTag(((IEnumLite)value).Number);
default: default:
throw new ArgumentOutOfRangeException("Invalid field type " + fieldType); throw new ArgumentOutOfRangeException("Invalid field type " + fieldType);
} }
} }
#endif
/// <summary> /// <summary>
/// Compute the number of bytes that would be needed to encode a tag. /// Compute the number of bytes that would be needed to encode a tag.
......
...@@ -37,7 +37,7 @@ namespace Google.ProtocolBuffers.Descriptors { ...@@ -37,7 +37,7 @@ namespace Google.ProtocolBuffers.Descriptors {
/// <summary> /// <summary>
/// Descriptor for an enum type in a .proto file. /// Descriptor for an enum type in a .proto file.
/// </summary> /// </summary>
public sealed class EnumDescriptor : IndexedDescriptorBase<EnumDescriptorProto, EnumOptions> { public sealed class EnumDescriptor : IndexedDescriptorBase<EnumDescriptorProto, EnumOptions>, IEnumLiteMap<EnumValueDescriptor> {
private readonly MessageDescriptor containingType; private readonly MessageDescriptor containingType;
private readonly IList<EnumValueDescriptor> values; private readonly IList<EnumValueDescriptor> values;
...@@ -72,11 +72,18 @@ namespace Google.ProtocolBuffers.Descriptors { ...@@ -72,11 +72,18 @@ namespace Google.ProtocolBuffers.Descriptors {
get { return values; } get { return values; }
} }
/// <summary>
/// Logic moved from FieldSet to continue current behavior
/// </summary>
public bool IsValidValue(IEnumLite value) {
return value is EnumValueDescriptor && ((EnumValueDescriptor)value).EnumDescriptor == this;
}
/// <summary> /// <summary>
/// Finds an enum value by number. If multiple enum values have the /// Finds an enum value by number. If multiple enum values have the
/// same number, this returns the first defined value with that number. /// same number, this returns the first defined value with that number.
/// </summary> /// </summary>
internal EnumValueDescriptor FindValueByNumber(int number) { public EnumValueDescriptor FindValueByNumber(int number) {
return File.DescriptorPool.FindEnumValueByNumber(this, number); return File.DescriptorPool.FindEnumValueByNumber(this, number);
} }
......
...@@ -36,7 +36,7 @@ namespace Google.ProtocolBuffers.Descriptors { ...@@ -36,7 +36,7 @@ namespace Google.ProtocolBuffers.Descriptors {
/// <summary> /// <summary>
/// Descriptor for a single enum value within an enum in a .proto file. /// Descriptor for a single enum value within an enum in a .proto file.
/// </summary> /// </summary>
public sealed class EnumValueDescriptor : IndexedDescriptorBase<EnumValueDescriptorProto, EnumValueOptions> { public sealed class EnumValueDescriptor : IndexedDescriptorBase<EnumValueDescriptorProto, EnumValueOptions>, IEnumLite {
private readonly EnumDescriptor enumDescriptor; private readonly EnumDescriptor enumDescriptor;
......
...@@ -40,7 +40,7 @@ namespace Google.ProtocolBuffers.Descriptors { ...@@ -40,7 +40,7 @@ namespace Google.ProtocolBuffers.Descriptors {
/// <summary> /// <summary>
/// Descriptor for a field or extension within a message in a .proto file. /// Descriptor for a field or extension within a message in a .proto file.
/// </summary> /// </summary>
public sealed class FieldDescriptor : IndexedDescriptorBase<FieldDescriptorProto, FieldOptions>, IComparable<FieldDescriptor> { public sealed class FieldDescriptor : IndexedDescriptorBase<FieldDescriptorProto, FieldOptions>, IComparable<FieldDescriptor>, IFieldDescriptorLite {
private readonly MessageDescriptor extensionScope; private readonly MessageDescriptor extensionScope;
private EnumDescriptor enumType; private EnumDescriptor enumType;
...@@ -299,9 +299,26 @@ namespace Google.ProtocolBuffers.Descriptors { ...@@ -299,9 +299,26 @@ namespace Google.ProtocolBuffers.Descriptors {
} }
return FieldNumber - other.FieldNumber; return FieldNumber - other.FieldNumber;
} }
/// <summary> /// <summary>
/// Compares this descriptor with another one, ordering in "canonical" order
/// which simply means ascending order by field number. <paramref name="other"/>
/// must be a field of the same type, i.e. the <see cref="ContainingType"/> of
/// both fields must be the same.
/// </summary>
public int CompareTo(IFieldDescriptorLite other) {
return FieldNumber - other.FieldNumber;
}
IEnumLiteMap IFieldDescriptorLite.EnumType {
get { return EnumType; }
}
bool IFieldDescriptorLite.MessageSetWireFormat {
get { return ContainingType.Options.MessageSetWireFormat; }
}
/// <summary>
/// For enum fields, returns the field's type. /// For enum fields, returns the field's type.
/// </summary> /// </summary>
public EnumDescriptor EnumType { public EnumDescriptor EnumType {
......
...@@ -180,7 +180,7 @@ namespace Google.ProtocolBuffers { ...@@ -180,7 +180,7 @@ namespace Google.ProtocolBuffers {
} }
public override IDictionary<FieldDescriptor, object> AllFields { public override IDictionary<FieldDescriptor, object> AllFields {
get { return fields.AllFields; } get { return fields.AllFieldDescriptors; }
} }
public override bool HasField(FieldDescriptor field) { public override bool HasField(FieldDescriptor field) {
...@@ -216,7 +216,7 @@ namespace Google.ProtocolBuffers { ...@@ -216,7 +216,7 @@ namespace Google.ProtocolBuffers {
} }
public bool Initialized { public bool Initialized {
get { return fields.IsInitializedWithRespectTo(type); } get { return fields.IsInitializedWithRespectTo(type.Fields); }
} }
public override void WriteTo(CodedOutputStream output) { public override void WriteTo(CodedOutputStream output) {
...@@ -335,7 +335,7 @@ namespace Google.ProtocolBuffers { ...@@ -335,7 +335,7 @@ namespace Google.ProtocolBuffers {
} }
public override bool IsInitialized { public override bool IsInitialized {
get { return fields.IsInitializedWithRespectTo(type); } get { return fields.IsInitializedWithRespectTo(type.Fields); }
} }
public override Builder MergeFrom(CodedInputStream input, ExtensionRegistry extensionRegistry) { public override Builder MergeFrom(CodedInputStream input, ExtensionRegistry extensionRegistry) {
...@@ -354,7 +354,7 @@ namespace Google.ProtocolBuffers { ...@@ -354,7 +354,7 @@ namespace Google.ProtocolBuffers {
} }
public override IDictionary<FieldDescriptor, object> AllFields { public override IDictionary<FieldDescriptor, object> AllFields {
get { return fields.AllFields; } get { return fields.AllFieldDescriptors; }
} }
public override IBuilder CreateBuilderForField(FieldDescriptor field) { public override IBuilder CreateBuilderForField(FieldDescriptor field) {
......
using System;
using System.Collections.Generic;
using System.Text;
namespace Google.ProtocolBuffers {
///<summary>
///Interface for an enum value or value descriptor, to be used in FieldSet.
///The lite library stores enum values directly in FieldSets but the full
///library stores EnumValueDescriptors in order to better support reflection.
///</summary>
public interface IEnumLite {
int Number { get; }
}
///<summary>
///Interface for an object which maps integers to {@link EnumLite}s.
///{@link Descriptors.EnumDescriptor} implements this interface by mapping
///numbers to {@link Descriptors.EnumValueDescriptor}s. Additionally,
///every generated enum type has a static method internalGetValueMap() which
///returns an implementation of this type that maps numbers to enum values.
///</summary>
public interface IEnumLiteMap<T> : IEnumLiteMap
where T : IEnumLite {
T FindValueByNumber(int number);
}
public interface IEnumLiteMap {
bool IsValidValue(IEnumLite value);
}
}
...@@ -102,8 +102,8 @@ namespace Google.ProtocolBuffers { ...@@ -102,8 +102,8 @@ namespace Google.ProtocolBuffers {
public override IDictionary<FieldDescriptor, object> AllFields { public override IDictionary<FieldDescriptor, object> AllFields {
get { get {
IDictionary<FieldDescriptor, object> result = GetMutableFieldMap(); IDictionary<FieldDescriptor, object> result = GetMutableFieldMap();
foreach(KeyValuePair<FieldDescriptor, object> entry in extensions.AllFields) { foreach(KeyValuePair<IFieldDescriptorLite, object> entry in extensions.AllFields) {
result[entry.Key] = entry.Value; result[(FieldDescriptor)entry.Key] = entry.Value;
} }
return Dictionaries.AsReadOnly(result); return Dictionaries.AsReadOnly(result);
} }
...@@ -173,9 +173,9 @@ namespace Google.ProtocolBuffers { ...@@ -173,9 +173,9 @@ namespace Google.ProtocolBuffers {
/// TODO(jonskeet): See if we can improve this in terms of readability. /// TODO(jonskeet): See if we can improve this in terms of readability.
/// </summary> /// </summary>
protected class ExtensionWriter { protected class ExtensionWriter {
readonly IEnumerator<KeyValuePair<FieldDescriptor, object>> iterator; readonly IEnumerator<KeyValuePair<IFieldDescriptorLite, object>> iterator;
readonly FieldSet extensions; readonly FieldSet extensions;
KeyValuePair<FieldDescriptor, object>? next = null; KeyValuePair<IFieldDescriptorLite, object>? next = null;
internal ExtensionWriter(ExtendableMessage<TMessage, TBuilder> message) { internal ExtensionWriter(ExtendableMessage<TMessage, TBuilder> message) {
extensions = message.extensions; extensions = message.extensions;
......
...@@ -39,6 +39,20 @@ using Google.ProtocolBuffers.Collections; ...@@ -39,6 +39,20 @@ using Google.ProtocolBuffers.Collections;
using Google.ProtocolBuffers.Descriptors; using Google.ProtocolBuffers.Descriptors;
namespace Google.ProtocolBuffers { namespace Google.ProtocolBuffers {
public interface IFieldDescriptorLite : IComparable<IFieldDescriptorLite> {
bool IsRepeated { get; }
bool IsRequired { get; }
bool IsPacked { get; }
bool IsExtension { get; }
bool MessageSetWireFormat { get; } //field.ContainingType.Options.MessageSetWireFormat
int FieldNumber { get; }
IEnumLiteMap EnumType { get; }
FieldType FieldType { get; }
MappedType MappedType { get; }
object DefaultValue { get; }
}
/// <summary> /// <summary>
/// A class which represents an arbitrary set of fields of some message type. /// A class which represents an arbitrary set of fields of some message type.
/// This is used to implement DynamicMessage, and also to represent extensions /// This is used to implement DynamicMessage, and also to represent extensions
...@@ -56,17 +70,17 @@ namespace Google.ProtocolBuffers { ...@@ -56,17 +70,17 @@ namespace Google.ProtocolBuffers {
/// </summary> /// </summary>
internal sealed class FieldSet { internal sealed class FieldSet {
private static readonly FieldSet defaultInstance = new FieldSet(new Dictionary<FieldDescriptor, object>()).MakeImmutable(); private static readonly FieldSet defaultInstance = new FieldSet(new Dictionary<IFieldDescriptorLite, object>()).MakeImmutable();
private IDictionary<FieldDescriptor, object> fields; private IDictionary<IFieldDescriptorLite, object> fields;
private FieldSet(IDictionary<FieldDescriptor, object> fields) { private FieldSet(IDictionary<IFieldDescriptorLite, object> fields) {
this.fields = fields; this.fields = fields;
} }
public static FieldSet CreateInstance() { public static FieldSet CreateInstance() {
// Use SortedList to keep fields in the canonical order // Use SortedList to keep fields in the canonical order
return new FieldSet(new SortedList<FieldDescriptor, object>()); return new FieldSet(new SortedList<IFieldDescriptorLite, object>());
} }
/// <summary> /// <summary>
...@@ -85,8 +99,8 @@ namespace Google.ProtocolBuffers { ...@@ -85,8 +99,8 @@ namespace Google.ProtocolBuffers {
} }
if (hasRepeats) { if (hasRepeats) {
var tmp = new SortedList<FieldDescriptor, object>(); var tmp = new SortedList<IFieldDescriptorLite, object>();
foreach (KeyValuePair<FieldDescriptor, object> entry in fields) { foreach (KeyValuePair<IFieldDescriptorLite, object> entry in fields) {
IList<object> list = entry.Value as IList<object>; IList<object> list = entry.Value as IList<object>;
tmp[entry.Key] = list == null ? entry.Value : Lists.AsReadOnly(list); tmp[entry.Key] = list == null ? entry.Value : Lists.AsReadOnly(list);
} }
...@@ -110,14 +124,26 @@ namespace Google.ProtocolBuffers { ...@@ -110,14 +124,26 @@ namespace Google.ProtocolBuffers {
/// is immutable, the entries may not be (i.e. any repeated values are represented by /// is immutable, the entries may not be (i.e. any repeated values are represented by
/// mutable lists). The behaviour is not specified if the contents are mutated. /// mutable lists). The behaviour is not specified if the contents are mutated.
/// </summary> /// </summary>
internal IDictionary<FieldDescriptor, object> AllFields { internal IDictionary<IFieldDescriptorLite, object> AllFields {
get { return Dictionaries.AsReadOnly(fields); } get { return Dictionaries.AsReadOnly(fields); }
} }
#if !LITE
/// <summary>
/// Force coercion to full descriptor dictionary.
/// </summary>
internal IDictionary<Descriptors.FieldDescriptor, object> AllFieldDescriptors {
get {
SortedList<Descriptors.FieldDescriptor, object> copy = new SortedList<Google.ProtocolBuffers.Descriptors.FieldDescriptor, object>();
foreach (KeyValuePair<IFieldDescriptorLite, object> fd in fields)
copy.Add((Descriptors.FieldDescriptor)fd.Key, fd.Value);
return Dictionaries.AsReadOnly(copy);
}
}
#endif
/// <summary> /// <summary>
/// See <see cref="IMessage.HasField"/>. /// See <see cref="IMessageLite.HasField"/>.
/// </summary> /// </summary>
public bool HasField(FieldDescriptor field) { public bool HasField(IFieldDescriptorLite field) {
if (field.IsRepeated) { if (field.IsRepeated) {
throw new ArgumentException("HasField() can only be called on non-repeated fields."); throw new ArgumentException("HasField() can only be called on non-repeated fields.");
} }
...@@ -133,7 +159,7 @@ namespace Google.ProtocolBuffers { ...@@ -133,7 +159,7 @@ namespace Google.ProtocolBuffers {
} }
/// <summary> /// <summary>
/// See <see cref="IMessage.Item(FieldDescriptor)"/> /// See <see cref="IMessageLite.Item(IFieldDescriptorLite)"/>
/// </summary> /// </summary>
/// <remarks> /// <remarks>
/// If the field is not set, the behaviour when fetching this property varies by field type: /// If the field is not set, the behaviour when fetching this property varies by field type:
...@@ -153,7 +179,7 @@ namespace Google.ProtocolBuffers { ...@@ -153,7 +179,7 @@ namespace Google.ProtocolBuffers {
/// to ensure it is of an appropriate type. /// to ensure it is of an appropriate type.
/// </remarks> /// </remarks>
/// ///
internal object this[FieldDescriptor field] { internal object this[IFieldDescriptorLite field] {
get { get {
object result; object result;
if (fields.TryGetValue(field, out result)) { if (fields.TryGetValue(field, out result)) {
...@@ -191,9 +217,9 @@ namespace Google.ProtocolBuffers { ...@@ -191,9 +217,9 @@ namespace Google.ProtocolBuffers {
} }
/// <summary> /// <summary>
/// See <see cref="IMessage.Item(FieldDescriptor,int)" /> /// See <see cref="IMessageLite.Item(IFieldDescriptorLite,int)" />
/// </summary> /// </summary>
internal object this[FieldDescriptor field, int index] { internal object this[IFieldDescriptorLite field, int index] {
get { get {
if (!field.IsRepeated) { if (!field.IsRepeated) {
throw new ArgumentException("Indexer specifying field and index can only be called on repeated fields."); throw new ArgumentException("Indexer specifying field and index can only be called on repeated fields.");
...@@ -217,7 +243,7 @@ namespace Google.ProtocolBuffers { ...@@ -217,7 +243,7 @@ namespace Google.ProtocolBuffers {
/// <summary> /// <summary>
/// See <see cref="IBuilder{TMessage, TBuilder}.AddRepeatedField" /> /// See <see cref="IBuilder{TMessage, TBuilder}.AddRepeatedField" />
/// </summary> /// </summary>
internal void AddRepeatedField(FieldDescriptor field, object value) { internal void AddRepeatedField(IFieldDescriptorLite field, object value) {
if (!field.IsRepeated) { if (!field.IsRepeated) {
throw new ArgumentException("AddRepeatedField can only be called on repeated fields."); throw new ArgumentException("AddRepeatedField can only be called on repeated fields.");
} }
...@@ -233,12 +259,12 @@ namespace Google.ProtocolBuffers { ...@@ -233,12 +259,12 @@ namespace Google.ProtocolBuffers {
/// <summary> /// <summary>
/// Returns an enumerator for the field map. Used to write the fields out. /// Returns an enumerator for the field map. Used to write the fields out.
/// </summary> /// </summary>
internal IEnumerator<KeyValuePair<FieldDescriptor, object>> GetEnumerator() { internal IEnumerator<KeyValuePair<IFieldDescriptorLite, object>> GetEnumerator() {
return fields.GetEnumerator(); return fields.GetEnumerator();
} }
/// <summary> /// <summary>
/// See <see cref="IMessage.IsInitialized" /> /// See <see cref="IMessageLite.IsInitialized" />
/// </summary> /// </summary>
/// <remarks> /// <remarks>
/// Since FieldSet itself does not have any way of knowing about /// Since FieldSet itself does not have any way of knowing about
...@@ -248,17 +274,17 @@ namespace Google.ProtocolBuffers { ...@@ -248,17 +274,17 @@ namespace Google.ProtocolBuffers {
/// </remarks> /// </remarks>
internal bool IsInitialized { internal bool IsInitialized {
get { get {
foreach (KeyValuePair<FieldDescriptor, object> entry in fields) { foreach (KeyValuePair<IFieldDescriptorLite, object> entry in fields) {
FieldDescriptor field = entry.Key; IFieldDescriptorLite field = entry.Key;
if (field.MappedType == MappedType.Message) { if (field.MappedType == MappedType.Message) {
if (field.IsRepeated) { if (field.IsRepeated) {
foreach(IMessage message in (IEnumerable) entry.Value) { foreach(IMessageLite message in (IEnumerable) entry.Value) {
if (!message.IsInitialized) { if (!message.IsInitialized) {
return false; return false;
} }
} }
} else { } else {
if (!((IMessage) entry.Value).IsInitialized) { if (!((IMessageLite)entry.Value).IsInitialized) {
return false; return false;
} }
} }
...@@ -273,8 +299,8 @@ namespace Google.ProtocolBuffers { ...@@ -273,8 +299,8 @@ namespace Google.ProtocolBuffers {
/// descriptor are present in this field set, as well as whether /// descriptor are present in this field set, as well as whether
/// all the embedded messages are themselves initialized. /// all the embedded messages are themselves initialized.
/// </summary> /// </summary>
internal bool IsInitializedWithRespectTo(MessageDescriptor type) { internal bool IsInitializedWithRespectTo(IEnumerable typeFields) {
foreach (FieldDescriptor field in type.Fields) { foreach (IFieldDescriptorLite field in typeFields) {
if (field.IsRequired && !HasField(field)) { if (field.IsRequired && !HasField(field)) {
return false; return false;
} }
...@@ -285,14 +311,14 @@ namespace Google.ProtocolBuffers { ...@@ -285,14 +311,14 @@ namespace Google.ProtocolBuffers {
/// <summary> /// <summary>
/// See <see cref="IBuilder{TMessage, TBuilder}.ClearField" /> /// See <see cref="IBuilder{TMessage, TBuilder}.ClearField" />
/// </summary> /// </summary>
public void ClearField(FieldDescriptor field) { public void ClearField(IFieldDescriptorLite field) {
fields.Remove(field); fields.Remove(field);
} }
/// <summary> /// <summary>
/// See <see cref="IMessage.GetRepeatedFieldCount" /> /// See <see cref="IMessageLite.GetRepeatedFieldCount" />
/// </summary> /// </summary>
public int GetRepeatedFieldCount(FieldDescriptor field) { public int GetRepeatedFieldCount(IFieldDescriptorLite field) {
if (!field.IsRepeated) { if (!field.IsRepeated) {
throw new ArgumentException("GetRepeatedFieldCount() can only be called on repeated fields."); throw new ArgumentException("GetRepeatedFieldCount() can only be called on repeated fields.");
} }
...@@ -300,64 +326,63 @@ namespace Google.ProtocolBuffers { ...@@ -300,64 +326,63 @@ namespace Google.ProtocolBuffers {
return ((IList<object>) this[field]).Count; return ((IList<object>) this[field]).Count;
} }
#if !LITE
/// <summary>
/// See <see cref="IBuilder{TMessage, TBuilder}.MergeFrom(IMessageLite)" />
/// </summary>
public void MergeFrom(IMessage other) {
foreach (KeyValuePair<Descriptors.FieldDescriptor, object> fd in other.AllFields)
MergeField(fd.Key, fd.Value);
}
#endif
/// <summary> /// <summary>
/// Implementation of both <c>MergeFrom</c> methods. /// Implementation of both <c>MergeFrom</c> methods.
/// </summary> /// </summary>
/// <param name="otherFields"></param> /// <param name="otherFields"></param>
private void MergeFields(IEnumerable<KeyValuePair<FieldDescriptor, object>> otherFields) { public void MergeFrom(FieldSet other) {
// Note: We don't attempt to verify that other's fields have valid // Note: We don't attempt to verify that other's fields have valid
// types. Doing so would be a losing battle. We'd have to verify // types. Doing so would be a losing battle. We'd have to verify
// all sub-messages as well, and we'd have to make copies of all of // all sub-messages as well, and we'd have to make copies of all of
// them to insure that they don't change after verification (since // them to insure that they don't change after verification (since
// the IMessage interface itself cannot enforce immutability of // the IMessageLite interface itself cannot enforce immutability of
// implementations). // implementations).
// TODO(jonskeet): Provide a function somewhere called MakeDeepCopy() // TODO(jonskeet): Provide a function somewhere called MakeDeepCopy()
// which allows people to make secure deep copies of messages. // which allows people to make secure deep copies of messages.
foreach (KeyValuePair<FieldDescriptor, object> entry in otherFields) { foreach (KeyValuePair<IFieldDescriptorLite, object> entry in other.fields) {
FieldDescriptor field = entry.Key; MergeField(entry.Key, entry.Value);
object existingValue;
fields.TryGetValue(field, out existingValue);
if (field.IsRepeated) {
if (existingValue == null) {
existingValue = new List<object>();
fields[field] = existingValue;
}
IList<object> list = (IList<object>) existingValue;
foreach (object otherValue in (IEnumerable) entry.Value) {
list.Add(otherValue);
}
} else if (field.MappedType == MappedType.Message && existingValue != null) {
IMessage existingMessage = (IMessage)existingValue;
IMessage merged = existingMessage.WeakToBuilder()
.WeakMergeFrom((IMessage) entry.Value)
.WeakBuild();
this[field] = merged;
} else {
this[field] = entry.Value;
}
} }
} }
/// <summary> private void MergeField(IFieldDescriptorLite field, object mergeValue) {
/// See <see cref="IBuilder{TMessage, TBuilder}.MergeFrom(IMessage)" /> object existingValue;
/// </summary> fields.TryGetValue(field, out existingValue);
public void MergeFrom(IMessage other) { if (field.IsRepeated) {
MergeFields(other.AllFields); if (existingValue == null) {
} existingValue = new List<object>();
fields[field] = existingValue;
/// <summary> }
/// Like <see cref="MergeFrom(IMessage)"/>, but merges from another <c>FieldSet</c>. IList<object> list = (IList<object>) existingValue;
/// </summary> foreach (object otherValue in (IEnumerable)mergeValue) {
public void MergeFrom(FieldSet other) { list.Add(otherValue);
MergeFields(other.fields); }
} else if (field.MappedType == MappedType.Message && existingValue != null) {
IMessageLite existingMessage = (IMessageLite)existingValue;
IMessageLite merged = existingMessage.WeakToBuilder()
.WeakMergeFrom((IMessageLite)mergeValue)
.WeakBuild();
this[field] = merged;
} else {
this[field] = mergeValue;
}
} }
/// <summary> /// <summary>
/// See <see cref="IMessage.WriteTo(CodedOutputStream)" />. /// See <see cref="IMessageLite.WriteTo(CodedOutputStream)" />.
/// </summary> /// </summary>
public void WriteTo(CodedOutputStream output) { public void WriteTo(CodedOutputStream output) {
foreach (KeyValuePair<FieldDescriptor, object> entry in fields) { foreach (KeyValuePair<IFieldDescriptorLite, object> entry in fields) {
WriteField(entry.Key, entry.Value, output); WriteField(entry.Key, entry.Value, output);
} }
} }
...@@ -365,9 +390,9 @@ namespace Google.ProtocolBuffers { ...@@ -365,9 +390,9 @@ namespace Google.ProtocolBuffers {
/// <summary> /// <summary>
/// Writes a single field to a CodedOutputStream. /// Writes a single field to a CodedOutputStream.
/// </summary> /// </summary>
public void WriteField(FieldDescriptor field, Object value, CodedOutputStream output) { public void WriteField(IFieldDescriptorLite field, Object value, CodedOutputStream output) {
if (field.IsExtension && field.ContainingType.Options.MessageSetWireFormat) { if (field.IsExtension && field.MessageSetWireFormat) {
output.WriteMessageSetExtension(field.FieldNumber, (IMessage) value); output.WriteMessageSetExtension(field.FieldNumber, (IMessageLite) value);
} else { } else {
if (field.IsRepeated) { if (field.IsRepeated) {
IEnumerable valueList = (IEnumerable) value; IEnumerable valueList = (IEnumerable) value;
...@@ -395,18 +420,18 @@ namespace Google.ProtocolBuffers { ...@@ -395,18 +420,18 @@ namespace Google.ProtocolBuffers {
} }
/// <summary> /// <summary>
/// See <see cref="IMessage.SerializedSize" />. It's up to the caller to /// See <see cref="IMessageLite.SerializedSize" />. It's up to the caller to
/// cache the resulting size if desired. /// cache the resulting size if desired.
/// </summary> /// </summary>
public int SerializedSize { public int SerializedSize {
get { get {
int size = 0; int size = 0;
foreach (KeyValuePair<FieldDescriptor, object> entry in fields) { foreach (KeyValuePair<IFieldDescriptorLite, object> entry in fields) {
FieldDescriptor field = entry.Key; IFieldDescriptorLite field = entry.Key;
object value = entry.Value; object value = entry.Value;
if (field.IsExtension && field.ContainingType.Options.MessageSetWireFormat) { if (field.IsExtension && field.MessageSetWireFormat) {
size += CodedOutputStream.ComputeMessageSetExtensionSize(field.FieldNumber, (IMessage)value); size += CodedOutputStream.ComputeMessageSetExtensionSize(field.FieldNumber, (IMessageLite)value);
} else { } else {
if (field.IsRepeated) { if (field.IsRepeated) {
IEnumerable valueList = (IEnumerable)value; IEnumerable valueList = (IEnumerable)value;
...@@ -440,7 +465,7 @@ namespace Google.ProtocolBuffers { ...@@ -440,7 +465,7 @@ namespace Google.ProtocolBuffers {
/// </remarks> /// </remarks>
/// <exception cref="ArgumentException">The value is not of the right type.</exception> /// <exception cref="ArgumentException">The value is not of the right type.</exception>
/// <exception cref="ArgumentNullException">The value is null.</exception> /// <exception cref="ArgumentNullException">The value is null.</exception>
private static void VerifyType(FieldDescriptor field, object value) { private static void VerifyType(IFieldDescriptorLite field, object value) {
ThrowHelper.ThrowIfNull(value, "value"); ThrowHelper.ThrowIfNull(value, "value");
bool isValid = false; bool isValid = false;
switch (field.MappedType) { switch (field.MappedType) {
...@@ -454,12 +479,15 @@ namespace Google.ProtocolBuffers { ...@@ -454,12 +479,15 @@ namespace Google.ProtocolBuffers {
case MappedType.String: isValid = value is string; break; case MappedType.String: isValid = value is string; break;
case MappedType.ByteString: isValid = value is ByteString; break; case MappedType.ByteString: isValid = value is ByteString; break;
case MappedType.Enum: case MappedType.Enum:
EnumValueDescriptor enumValue = value as EnumValueDescriptor; IEnumLite enumValue = value as IEnumLite;
isValid = enumValue != null && enumValue.EnumDescriptor == field.EnumType; isValid = enumValue != null && field.EnumType.IsValidValue(enumValue);
break; break;
case MappedType.Message: case MappedType.Message:
IMessage messageValue = value as IMessage; IMessageLite messageValue = value as IMessageLite;
isValid = messageValue != null && messageValue.DescriptorForType == field.MessageType; isValid = messageValue != null;
#if !LITE
isValid = isValid && ((IMessage)messageValue).DescriptorForType == ((Google.ProtocolBuffers.Descriptors.FieldDescriptor)field).MessageType;
#endif
break; break;
} }
...@@ -468,10 +496,16 @@ namespace Google.ProtocolBuffers { ...@@ -468,10 +496,16 @@ namespace Google.ProtocolBuffers {
// the stack trace which exact call failed, since the whole chain is // the stack trace which exact call failed, since the whole chain is
// considered one line of code. So, let's make sure to include the // considered one line of code. So, let's make sure to include the
// field name and other useful info in the exception. // field name and other useful info in the exception.
throw new ArgumentException("Wrong object type used with protocol message reflection. " string message = "Wrong object type used with protocol message reflection.";
+ "Message type \"" + field.ContainingType.FullName #if !LITE
+ "\", field \"" + (field.IsExtension ? field.FullName : field.Name) Google.ProtocolBuffers.Descriptors.FieldDescriptor fieldinfo = field as Google.ProtocolBuffers.Descriptors.FieldDescriptor;
+ "\", value was type \"" + value.GetType().Name + "\"."); if (fieldinfo != null) {
message += "Message type \"" + fieldinfo.ContainingType.FullName;
message += "\", field \"" + (fieldinfo.IsExtension ? fieldinfo.FullName : fieldinfo.Name);
message += "\", value was type \"" + value.GetType().Name + "\".";
}
#endif
throw new ArgumentException(message);
} }
} }
} }
......
using System; using System;
using Google.ProtocolBuffers.Descriptors;
namespace Google.ProtocolBuffers { namespace Google.ProtocolBuffers {
...@@ -7,4 +8,111 @@ namespace Google.ProtocolBuffers { ...@@ -7,4 +8,111 @@ namespace Google.ProtocolBuffers {
object ContainingType { get; } object ContainingType { get; }
IMessageLite MessageDefaultInstance { get; } IMessageLite MessageDefaultInstance { get; }
} }
public class ExtensionDescriptorLite {
private readonly EnumLiteMap enumTypeMap;
private readonly int number;
private readonly FieldType type;
private readonly bool isRepeated;
private readonly bool isPacked;
public ExtensionDescriptorLite(EnumLiteMap enumTypeMap, int number, FieldType type, bool isRepeated, bool isPacked) {
this.enumTypeMap = enumTypeMap;
this.number = number;
this.type = type;
this.isRepeated = isRepeated;
this.isPacked = isPacked;
}
public int Number {
get { return number; }
}
}
public class EnumLiteMap { }
public class GeneratedExtensionLite<TContainingType, TExtensionType> : IGeneratedExtensionLite
where TContainingType : IMessageLite {
private readonly TContainingType containingTypeDefaultInstance;
private readonly TExtensionType defaultValue;
private readonly IMessageLite messageDefaultInstance;
private readonly ExtensionDescriptorLite descriptor;
// We can't always initialize a GeneratedExtension when we first construct
// it due to initialization order difficulties (namely, the default
// instances may not have been constructed yet). So, we construct an
// uninitialized GeneratedExtension once, then call internalInit() on it
// later. Generated code will always call internalInit() on all extensions
// as part of the static initialization code, and internalInit() throws an
// exception if called more than once, so this method is useless to users.
protected GeneratedExtensionLite(
TContainingType containingTypeDefaultInstance,
TExtensionType defaultValue,
IMessageLite messageDefaultInstance,
ExtensionDescriptorLite descriptor) {
this.containingTypeDefaultInstance = containingTypeDefaultInstance;
this.messageDefaultInstance = messageDefaultInstance;
this.defaultValue = defaultValue;
this.descriptor = descriptor;
}
/** For use by generated code only. */
public GeneratedExtensionLite(
TContainingType containingTypeDefaultInstance,
TExtensionType defaultValue,
IMessageLite messageDefaultInstance,
EnumLiteMap enumTypeMap,
int number,
FieldType type)
: this(containingTypeDefaultInstance, defaultValue, messageDefaultInstance,
new ExtensionDescriptorLite(enumTypeMap, number, type,
false /* isRepeated */, false /* isPacked */)) {
}
/** For use by generated code only. */
public GeneratedExtensionLite(
TContainingType containingTypeDefaultInstance,
TExtensionType defaultValue,
IMessageLite messageDefaultInstance,
EnumLiteMap enumTypeMap,
int number,
FieldType type,
bool isPacked)
: this(containingTypeDefaultInstance, defaultValue, messageDefaultInstance,
new ExtensionDescriptorLite(enumTypeMap, number, type,
true /* isRepeated */, isPacked)) {
}
/// <summary>
/// used for the extension registry
/// </summary>
object IGeneratedExtensionLite.ContainingType {
get { return ContainingTypeDefaultInstance; }
}
/**
* Default instance of the type being extended, used to identify that type.
*/
public TContainingType ContainingTypeDefaultInstance {
get {
return containingTypeDefaultInstance;
}
}
/** Get the field number. */
public int Number {
get {
return descriptor.Number;
}
}
/**
* If the extension is an embedded message, this is the default instance of
* that type.
*/
public IMessageLite MessageDefaultInstance {
get {
return messageDefaultInstance;
}
}
}
} }
\ No newline at end of file
...@@ -90,6 +90,7 @@ ...@@ -90,6 +90,7 @@
<Compile Include="Descriptors\PackageDescriptor.cs" /> <Compile Include="Descriptors\PackageDescriptor.cs" />
<Compile Include="Descriptors\ServiceDescriptor.cs" /> <Compile Include="Descriptors\ServiceDescriptor.cs" />
<Compile Include="DynamicMessage.cs" /> <Compile Include="DynamicMessage.cs" />
<Compile Include="EnumLite.cs" />
<Compile Include="ExtendableBuilder.cs" /> <Compile Include="ExtendableBuilder.cs" />
<Compile Include="ExtendableMessage.cs" /> <Compile Include="ExtendableMessage.cs" />
<Compile Include="ExtensionInfo.cs"> <Compile Include="ExtensionInfo.cs">
......
...@@ -46,6 +46,8 @@ ...@@ -46,6 +46,8 @@
<ItemGroup> <ItemGroup>
<Reference Include="mscorlib" /> <Reference Include="mscorlib" />
<Reference Include="System" /> <Reference Include="System" />
<Reference Include="System.Data" />
<Reference Include="System.Xml" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
</ItemGroup> </ItemGroup>
...@@ -55,7 +57,17 @@ ...@@ -55,7 +57,17 @@
<ItemGroup> <ItemGroup>
<Compile Include="AbstractBuilderLite.cs" /> <Compile Include="AbstractBuilderLite.cs" />
<Compile Include="AbstractMessageLite.cs" /> <Compile Include="AbstractMessageLite.cs" />
<Compile Include="Collections\Dictionaries.cs" />
<Compile Include="Collections\Lists.cs" />
<Compile Include="Descriptors\FieldMappingAttribute.cs" />
<Compile Include="Descriptors\FieldType.cs" />
<Compile Include="Descriptors\MappedType.cs" />
<Compile Include="EnumLite.cs" />
<Compile Include="ExtendableMessageLite.cs" />
<Compile Include="FieldSet.cs" />
<Compile Include="GeneratedBuilderLite.cs" />
<Compile Include="GeneratedExtensionLite.cs" /> <Compile Include="GeneratedExtensionLite.cs" />
<Compile Include="GeneratedMessageLite.cs" />
<Compile Include="Properties\AssemblyInfo.cs" /> <Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="ByteString.cs" /> <Compile Include="ByteString.cs" />
<Compile Include="CodedInputStream.cs" /> <Compile Include="CodedInputStream.cs" />
...@@ -66,6 +78,7 @@ ...@@ -66,6 +78,7 @@
<SubType>Code</SubType> <SubType>Code</SubType>
</Compile> </Compile>
<Compile Include="InvalidProtocolBufferException.cs" /> <Compile Include="InvalidProtocolBufferException.cs" />
<Compile Include="ThrowHelper.cs" />
<Compile Include="UninitializedMessageException.cs" /> <Compile Include="UninitializedMessageException.cs" />
<Compile Include="WireFormat.cs" /> <Compile Include="WireFormat.cs" />
</ItemGroup> </ItemGroup>
......
...@@ -54,9 +54,13 @@ ...@@ -54,9 +54,13 @@
<Reference Include="System.Xml" /> <Reference Include="System.Xml" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<Compile Include="..\..\tmp\UnitTestLiteProtoFile.cs">
<Link>UnitTestLiteProtoFile.cs</Link>
</Compile>
<Compile Include="..\ProtocolBuffers.Test\Properties\AssemblyInfo.cs"> <Compile Include="..\ProtocolBuffers.Test\Properties\AssemblyInfo.cs">
<Link>Properties\AssemblyInfo.cs</Link> <Link>Properties\AssemblyInfo.cs</Link>
</Compile> </Compile>
<Compile Include="Todo.cs" />
<None Include="TestProtos\UnittestLite.cs" /> <None Include="TestProtos\UnittestLite.cs" />
<None Include="TestProtos\UnittestLiteImportsNonlite.cs" /> <None Include="TestProtos\UnittestLiteImportsNonlite.cs" />
</ItemGroup> </ItemGroup>
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment