Implementation work for Lite runtime and generator

pull/288/head
csharptest 14 years ago
parent 64bfac2825
commit 804b6d842e
  1. 6
      src/ProtoGen/Helpers.cs
  2. 69
      src/ProtoGen/MessageGenerator.cs
  3. 8
      src/ProtoGen/SourceGeneratorBase.cs
  4. 31
      src/ProtoGen/UmbrellaClassGenerator.cs
  5. 5
      src/ProtocolBuffers/CodedInputStream.cs
  6. 31
      src/ProtocolBuffers/CodedOutputStream.cs
  7. 11
      src/ProtocolBuffers/Descriptors/EnumDescriptor.cs
  8. 2
      src/ProtocolBuffers/Descriptors/EnumValueDescriptor.cs
  9. 21
      src/ProtocolBuffers/Descriptors/FieldDescriptor.cs
  10. 8
      src/ProtocolBuffers/DynamicMessage.cs
  11. 31
      src/ProtocolBuffers/EnumLite.cs
  12. 8
      src/ProtocolBuffers/ExtendableMessage.cs
  13. 196
      src/ProtocolBuffers/FieldSet.cs
  14. 108
      src/ProtocolBuffers/GeneratedExtensionLite.cs
  15. 1
      src/ProtocolBuffers/ProtocolBuffers.csproj
  16. 13
      src/ProtocolBuffers/ProtocolBuffersLite.csproj
  17. 4
      src/ProtocolBuffersLite.Test/ProtocolBuffersLite.Test.csproj

@ -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;");
}
}
}

@ -69,12 +69,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 +85,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 +114,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",
UseLiteRuntime ? "Lite" : "");
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 +133,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);

@ -40,8 +40,16 @@ namespace Google.ProtocolBuffers.ProtoGen {
private readonly T descriptor;
protected readonly bool OptimizeSpeed;
protected readonly bool OptimizeSize;
protected readonly bool UseLiteRuntime;
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;
}
protected T Descriptor {

@ -83,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();
@ -111,7 +115,12 @@ namespace Google.ProtocolBuffers.ProtoGen {
private void WriteIntroduction(TextGenerator writer) {
writer.WriteLine("// Generated by the protocol buffer compiler. DO NOT EDIT!");
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 != "") {
writer.WriteLine("namespace {0} {{", Descriptor.CSharpOptions.Namespace);
@ -211,5 +220,23 @@ namespace Google.ProtocolBuffers.ProtoGen {
writer.WriteLine("#endregion");
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;
using System.Collections.Generic;
using System.IO;
using System.Text;
#if !LITE
using Google.ProtocolBuffers.Descriptors;
#endif
namespace Google.ProtocolBuffers {
@ -363,7 +361,7 @@ namespace Google.ProtocolBuffers {
public long ReadSInt64() {
return DecodeZigZag64(ReadRawVarint64());
}
#if !LITE
/// <summary>
/// Reads a field of any primitive type. Enums, groups and embedded
/// messages are not handled by this method.
@ -397,7 +395,6 @@ namespace Google.ProtocolBuffers {
throw new ArgumentOutOfRangeException("Invalid field type " + fieldType);
}
}
#endif
#endregion
#region Underlying reading primitives

@ -35,9 +35,8 @@
using System;
using System.IO;
using System.Text;
#if !LITE
using Google.ProtocolBuffers.Descriptors;
#endif
namespace Google.ProtocolBuffers {
/// <summary>
@ -279,7 +278,6 @@ namespace Google.ProtocolBuffers {
WriteTag(WireFormat.MessageSetField.Item, WireFormat.WireType.EndGroup);
}
#if !LITE
public void WriteField(FieldType fieldType, int fieldNumber, object value) {
switch (fieldType) {
case FieldType.Double: WriteDouble(fieldNumber, (double)value); break;
@ -291,15 +289,15 @@ namespace Google.ProtocolBuffers {
case FieldType.Fixed32: WriteFixed32(fieldNumber, (uint)value); break;
case FieldType.Bool: WriteBool(fieldNumber, (bool)value); break;
case FieldType.String: WriteString(fieldNumber, (string)value); break;
case FieldType.Group: WriteGroup(fieldNumber, (IMessage)value); break;
case FieldType.Message: WriteMessage(fieldNumber, (IMessage)value); break;
case FieldType.Group: WriteGroup(fieldNumber, (IMessageLite)value); break;
case FieldType.Message: WriteMessage(fieldNumber, (IMessageLite)value); break;
case FieldType.Bytes: WriteBytes(fieldNumber, (ByteString)value); break;
case FieldType.UInt32: WriteUInt32(fieldNumber, (uint)value); break;
case FieldType.SFixed32: WriteSFixed32(fieldNumber, (int)value); break;
case FieldType.SFixed64: WriteSFixed64(fieldNumber, (long)value); break;
case FieldType.SInt32: WriteSInt32(fieldNumber, (int)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;
}
}
@ -315,19 +313,18 @@ namespace Google.ProtocolBuffers {
case FieldType.Fixed32: WriteFixed32NoTag((uint)value); break;
case FieldType.Bool: WriteBoolNoTag((bool)value); break;
case FieldType.String: WriteStringNoTag((string)value); break;
case FieldType.Group: WriteGroupNoTag((IMessage)value); break;
case FieldType.Message: WriteMessageNoTag((IMessage)value); break;
case FieldType.Group: WriteGroupNoTag((IMessageLite)value); break;
case FieldType.Message: WriteMessageNoTag((IMessageLite)value); break;
case FieldType.Bytes: WriteBytesNoTag((ByteString)value); break;
case FieldType.UInt32: WriteUInt32NoTag((uint)value); break;
case FieldType.SFixed32: WriteSFixed32NoTag((int)value); break;
case FieldType.SFixed64: WriteSFixed64NoTag((long)value); break;
case FieldType.SInt32: WriteSInt32NoTag((int)value); break;
case FieldType.SInt64: WriteSInt64NoTag((long)value); break;
case FieldType.Enum: WriteEnumNoTag(((EnumValueDescriptor)value).Number);
case FieldType.Enum: WriteEnumNoTag(((IEnumLite)value).Number);
break;
}
}
#endif
#endregion
#region Writing of values without tags
@ -995,7 +992,6 @@ namespace Google.ProtocolBuffers {
return 10;
}
#if !LITE
/// <summary>
/// Compute the number of bytes that would be needed to encode a
/// field of arbitrary type, including the tag, to the stream.
@ -1011,15 +1007,15 @@ namespace Google.ProtocolBuffers {
case FieldType.Fixed32: return ComputeFixed32Size(fieldNumber, (uint)value);
case FieldType.Bool: return ComputeBoolSize(fieldNumber, (bool)value);
case FieldType.String: return ComputeStringSize(fieldNumber, (string)value);
case FieldType.Group: return ComputeGroupSize(fieldNumber, (IMessage)value);
case FieldType.Message: return ComputeMessageSize(fieldNumber, (IMessage)value);
case FieldType.Group: return ComputeGroupSize(fieldNumber, (IMessageLite)value);
case FieldType.Message: return ComputeMessageSize(fieldNumber, (IMessageLite)value);
case FieldType.Bytes: return ComputeBytesSize(fieldNumber, (ByteString)value);
case FieldType.UInt32: return ComputeUInt32Size(fieldNumber, (uint)value);
case FieldType.SFixed32: return ComputeSFixed32Size(fieldNumber, (int)value);
case FieldType.SFixed64: return ComputeSFixed64Size(fieldNumber, (long)value);
case FieldType.SInt32: return ComputeSInt32Size(fieldNumber, (int)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:
throw new ArgumentOutOfRangeException("Invalid field type " + fieldType);
}
@ -1040,20 +1036,19 @@ namespace Google.ProtocolBuffers {
case FieldType.Fixed32: return ComputeFixed32SizeNoTag((uint)value);
case FieldType.Bool: return ComputeBoolSizeNoTag((bool)value);
case FieldType.String: return ComputeStringSizeNoTag((string)value);
case FieldType.Group: return ComputeGroupSizeNoTag((IMessage)value);
case FieldType.Message: return ComputeMessageSizeNoTag((IMessage)value);
case FieldType.Group: return ComputeGroupSizeNoTag((IMessageLite)value);
case FieldType.Message: return ComputeMessageSizeNoTag((IMessageLite)value);
case FieldType.Bytes: return ComputeBytesSizeNoTag((ByteString)value);
case FieldType.UInt32: return ComputeUInt32SizeNoTag((uint)value);
case FieldType.SFixed32: return ComputeSFixed32SizeNoTag((int)value);
case FieldType.SFixed64: return ComputeSFixed64SizeNoTag((long)value);
case FieldType.SInt32: return ComputeSInt32SizeNoTag((int)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:
throw new ArgumentOutOfRangeException("Invalid field type " + fieldType);
}
}
#endif
/// <summary>
/// Compute the number of bytes that would be needed to encode a tag.

@ -37,7 +37,7 @@ namespace Google.ProtocolBuffers.Descriptors {
/// <summary>
/// Descriptor for an enum type in a .proto file.
/// </summary>
public sealed class EnumDescriptor : IndexedDescriptorBase<EnumDescriptorProto, EnumOptions> {
public sealed class EnumDescriptor : IndexedDescriptorBase<EnumDescriptorProto, EnumOptions>, IEnumLiteMap<EnumValueDescriptor> {
private readonly MessageDescriptor containingType;
private readonly IList<EnumValueDescriptor> values;
@ -72,11 +72,18 @@ namespace Google.ProtocolBuffers.Descriptors {
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>
/// Finds an enum value by number. If multiple enum values have the
/// same number, this returns the first defined value with that number.
/// </summary>
internal EnumValueDescriptor FindValueByNumber(int number) {
public EnumValueDescriptor FindValueByNumber(int number) {
return File.DescriptorPool.FindEnumValueByNumber(this, number);
}

@ -36,7 +36,7 @@ namespace Google.ProtocolBuffers.Descriptors {
/// <summary>
/// Descriptor for a single enum value within an enum in a .proto file.
/// </summary>
public sealed class EnumValueDescriptor : IndexedDescriptorBase<EnumValueDescriptorProto, EnumValueOptions> {
public sealed class EnumValueDescriptor : IndexedDescriptorBase<EnumValueDescriptorProto, EnumValueOptions>, IEnumLite {
private readonly EnumDescriptor enumDescriptor;

@ -40,7 +40,7 @@ namespace Google.ProtocolBuffers.Descriptors {
/// <summary>
/// Descriptor for a field or extension within a message in a .proto file.
/// </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 EnumDescriptor enumType;
@ -299,9 +299,26 @@ namespace Google.ProtocolBuffers.Descriptors {
}
return FieldNumber - other.FieldNumber;
}
/// <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.
/// </summary>
public EnumDescriptor EnumType {

@ -180,7 +180,7 @@ namespace Google.ProtocolBuffers {
}
public override IDictionary<FieldDescriptor, object> AllFields {
get { return fields.AllFields; }
get { return fields.AllFieldDescriptors; }
}
public override bool HasField(FieldDescriptor field) {
@ -216,7 +216,7 @@ namespace Google.ProtocolBuffers {
}
public bool Initialized {
get { return fields.IsInitializedWithRespectTo(type); }
get { return fields.IsInitializedWithRespectTo(type.Fields); }
}
public override void WriteTo(CodedOutputStream output) {
@ -335,7 +335,7 @@ namespace Google.ProtocolBuffers {
}
public override bool IsInitialized {
get { return fields.IsInitializedWithRespectTo(type); }
get { return fields.IsInitializedWithRespectTo(type.Fields); }
}
public override Builder MergeFrom(CodedInputStream input, ExtensionRegistry extensionRegistry) {
@ -354,7 +354,7 @@ namespace Google.ProtocolBuffers {
}
public override IDictionary<FieldDescriptor, object> AllFields {
get { return fields.AllFields; }
get { return fields.AllFieldDescriptors; }
}
public override IBuilder CreateBuilderForField(FieldDescriptor field) {

@ -0,0 +1,31 @@
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 {
public override IDictionary<FieldDescriptor, object> AllFields {
get {
IDictionary<FieldDescriptor, object> result = GetMutableFieldMap();
foreach(KeyValuePair<FieldDescriptor, object> entry in extensions.AllFields) {
result[entry.Key] = entry.Value;
foreach(KeyValuePair<IFieldDescriptorLite, object> entry in extensions.AllFields) {
result[(FieldDescriptor)entry.Key] = entry.Value;
}
return Dictionaries.AsReadOnly(result);
}
@ -173,9 +173,9 @@ namespace Google.ProtocolBuffers {
/// TODO(jonskeet): See if we can improve this in terms of readability.
/// </summary>
protected class ExtensionWriter {
readonly IEnumerator<KeyValuePair<FieldDescriptor, object>> iterator;
readonly IEnumerator<KeyValuePair<IFieldDescriptorLite, object>> iterator;
readonly FieldSet extensions;
KeyValuePair<FieldDescriptor, object>? next = null;
KeyValuePair<IFieldDescriptorLite, object>? next = null;
internal ExtensionWriter(ExtendableMessage<TMessage, TBuilder> message) {
extensions = message.extensions;

@ -39,6 +39,20 @@ using Google.ProtocolBuffers.Collections;
using Google.ProtocolBuffers.Descriptors;
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>
/// A class which represents an arbitrary set of fields of some message type.
/// This is used to implement DynamicMessage, and also to represent extensions
@ -56,17 +70,17 @@ namespace Google.ProtocolBuffers {
/// </summary>
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;
}
public static FieldSet CreateInstance() {
// Use SortedList to keep fields in the canonical order
return new FieldSet(new SortedList<FieldDescriptor, object>());
return new FieldSet(new SortedList<IFieldDescriptorLite, object>());
}
/// <summary>
@ -85,8 +99,8 @@ namespace Google.ProtocolBuffers {
}
if (hasRepeats) {
var tmp = new SortedList<FieldDescriptor, object>();
foreach (KeyValuePair<FieldDescriptor, object> entry in fields) {
var tmp = new SortedList<IFieldDescriptorLite, object>();
foreach (KeyValuePair<IFieldDescriptorLite, object> entry in fields) {
IList<object> list = entry.Value as IList<object>;
tmp[entry.Key] = list == null ? entry.Value : Lists.AsReadOnly(list);
}
@ -110,14 +124,26 @@ namespace Google.ProtocolBuffers {
/// 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.
/// </summary>
internal IDictionary<FieldDescriptor, object> AllFields {
internal IDictionary<IFieldDescriptorLite, object> AllFields {
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>
/// See <see cref="IMessage.HasField"/>.
/// See <see cref="IMessageLite.HasField"/>.
/// </summary>
public bool HasField(FieldDescriptor field) {
public bool HasField(IFieldDescriptorLite field) {
if (field.IsRepeated) {
throw new ArgumentException("HasField() can only be called on non-repeated fields.");
}
@ -133,7 +159,7 @@ namespace Google.ProtocolBuffers {
}
/// <summary>
/// See <see cref="IMessage.Item(FieldDescriptor)"/>
/// See <see cref="IMessageLite.Item(IFieldDescriptorLite)"/>
/// </summary>
/// <remarks>
/// If the field is not set, the behaviour when fetching this property varies by field type:
@ -153,7 +179,7 @@ namespace Google.ProtocolBuffers {
/// to ensure it is of an appropriate type.
/// </remarks>
///
internal object this[FieldDescriptor field] {
internal object this[IFieldDescriptorLite field] {
get {
object result;
if (fields.TryGetValue(field, out result)) {
@ -191,9 +217,9 @@ namespace Google.ProtocolBuffers {
}
/// <summary>
/// See <see cref="IMessage.Item(FieldDescriptor,int)" />
/// See <see cref="IMessageLite.Item(IFieldDescriptorLite,int)" />
/// </summary>
internal object this[FieldDescriptor field, int index] {
internal object this[IFieldDescriptorLite field, int index] {
get {
if (!field.IsRepeated) {
throw new ArgumentException("Indexer specifying field and index can only be called on repeated fields.");
@ -217,7 +243,7 @@ namespace Google.ProtocolBuffers {
/// <summary>
/// See <see cref="IBuilder{TMessage, TBuilder}.AddRepeatedField" />
/// </summary>
internal void AddRepeatedField(FieldDescriptor field, object value) {
internal void AddRepeatedField(IFieldDescriptorLite field, object value) {
if (!field.IsRepeated) {
throw new ArgumentException("AddRepeatedField can only be called on repeated fields.");
}
@ -233,12 +259,12 @@ namespace Google.ProtocolBuffers {
/// <summary>
/// Returns an enumerator for the field map. Used to write the fields out.
/// </summary>
internal IEnumerator<KeyValuePair<FieldDescriptor, object>> GetEnumerator() {
internal IEnumerator<KeyValuePair<IFieldDescriptorLite, object>> GetEnumerator() {
return fields.GetEnumerator();
}
/// <summary>
/// See <see cref="IMessage.IsInitialized" />
/// See <see cref="IMessageLite.IsInitialized" />
/// </summary>
/// <remarks>
/// Since FieldSet itself does not have any way of knowing about
@ -248,17 +274,17 @@ namespace Google.ProtocolBuffers {
/// </remarks>
internal bool IsInitialized {
get {
foreach (KeyValuePair<FieldDescriptor, object> entry in fields) {
FieldDescriptor field = entry.Key;
foreach (KeyValuePair<IFieldDescriptorLite, object> entry in fields) {
IFieldDescriptorLite field = entry.Key;
if (field.MappedType == MappedType.Message) {
if (field.IsRepeated) {
foreach(IMessage message in (IEnumerable) entry.Value) {
foreach(IMessageLite message in (IEnumerable) entry.Value) {
if (!message.IsInitialized) {
return false;
}
}
} else {
if (!((IMessage) entry.Value).IsInitialized) {
if (!((IMessageLite)entry.Value).IsInitialized) {
return false;
}
}
@ -273,8 +299,8 @@ namespace Google.ProtocolBuffers {
/// descriptor are present in this field set, as well as whether
/// all the embedded messages are themselves initialized.
/// </summary>
internal bool IsInitializedWithRespectTo(MessageDescriptor type) {
foreach (FieldDescriptor field in type.Fields) {
internal bool IsInitializedWithRespectTo(IEnumerable typeFields) {
foreach (IFieldDescriptorLite field in typeFields) {
if (field.IsRequired && !HasField(field)) {
return false;
}
@ -285,14 +311,14 @@ namespace Google.ProtocolBuffers {
/// <summary>
/// See <see cref="IBuilder{TMessage, TBuilder}.ClearField" />
/// </summary>
public void ClearField(FieldDescriptor field) {
public void ClearField(IFieldDescriptorLite field) {
fields.Remove(field);
}
/// <summary>
/// See <see cref="IMessage.GetRepeatedFieldCount" />
/// See <see cref="IMessageLite.GetRepeatedFieldCount" />
/// </summary>
public int GetRepeatedFieldCount(FieldDescriptor field) {
public int GetRepeatedFieldCount(IFieldDescriptorLite field) {
if (!field.IsRepeated) {
throw new ArgumentException("GetRepeatedFieldCount() can only be called on repeated fields.");
}
@ -300,64 +326,63 @@ namespace Google.ProtocolBuffers {
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>
/// Implementation of both <c>MergeFrom</c> methods.
/// </summary>
/// <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
// 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
// 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).
// TODO(jonskeet): Provide a function somewhere called MakeDeepCopy()
// which allows people to make secure deep copies of messages.
foreach (KeyValuePair<FieldDescriptor, object> entry in otherFields) {
FieldDescriptor field = entry.Key;
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;
}
foreach (KeyValuePair<IFieldDescriptorLite, object> entry in other.fields) {
MergeField(entry.Key, entry.Value);
}
}
/// <summary>
/// See <see cref="IBuilder{TMessage, TBuilder}.MergeFrom(IMessage)" />
/// </summary>
public void MergeFrom(IMessage other) {
MergeFields(other.AllFields);
}
/// <summary>
/// Like <see cref="MergeFrom(IMessage)"/>, but merges from another <c>FieldSet</c>.
/// </summary>
public void MergeFrom(FieldSet other) {
MergeFields(other.fields);
private void MergeField(IFieldDescriptorLite field, object mergeValue) {
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)mergeValue) {
list.Add(otherValue);
}
} 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>
/// See <see cref="IMessage.WriteTo(CodedOutputStream)" />.
/// See <see cref="IMessageLite.WriteTo(CodedOutputStream)" />.
/// </summary>
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);
}
}
@ -365,9 +390,9 @@ namespace Google.ProtocolBuffers {
/// <summary>
/// Writes a single field to a CodedOutputStream.
/// </summary>
public void WriteField(FieldDescriptor field, Object value, CodedOutputStream output) {
if (field.IsExtension && field.ContainingType.Options.MessageSetWireFormat) {
output.WriteMessageSetExtension(field.FieldNumber, (IMessage) value);
public void WriteField(IFieldDescriptorLite field, Object value, CodedOutputStream output) {
if (field.IsExtension && field.MessageSetWireFormat) {
output.WriteMessageSetExtension(field.FieldNumber, (IMessageLite) value);
} else {
if (field.IsRepeated) {
IEnumerable valueList = (IEnumerable) value;
@ -395,18 +420,18 @@ namespace Google.ProtocolBuffers {
}
/// <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.
/// </summary>
public int SerializedSize {
get {
int size = 0;
foreach (KeyValuePair<FieldDescriptor, object> entry in fields) {
FieldDescriptor field = entry.Key;
foreach (KeyValuePair<IFieldDescriptorLite, object> entry in fields) {
IFieldDescriptorLite field = entry.Key;
object value = entry.Value;
if (field.IsExtension && field.ContainingType.Options.MessageSetWireFormat) {
size += CodedOutputStream.ComputeMessageSetExtensionSize(field.FieldNumber, (IMessage)value);
if (field.IsExtension && field.MessageSetWireFormat) {
size += CodedOutputStream.ComputeMessageSetExtensionSize(field.FieldNumber, (IMessageLite)value);
} else {
if (field.IsRepeated) {
IEnumerable valueList = (IEnumerable)value;
@ -440,7 +465,7 @@ namespace Google.ProtocolBuffers {
/// </remarks>
/// <exception cref="ArgumentException">The value is not of the right type.</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");
bool isValid = false;
switch (field.MappedType) {
@ -454,12 +479,15 @@ namespace Google.ProtocolBuffers {
case MappedType.String: isValid = value is string; break;
case MappedType.ByteString: isValid = value is ByteString; break;
case MappedType.Enum:
EnumValueDescriptor enumValue = value as EnumValueDescriptor;
isValid = enumValue != null && enumValue.EnumDescriptor == field.EnumType;
IEnumLite enumValue = value as IEnumLite;
isValid = enumValue != null && field.EnumType.IsValidValue(enumValue);
break;
case MappedType.Message:
IMessage messageValue = value as IMessage;
isValid = messageValue != null && messageValue.DescriptorForType == field.MessageType;
IMessageLite messageValue = value as IMessageLite;
isValid = messageValue != null;
#if !LITE
isValid = isValid && ((IMessage)messageValue).DescriptorForType == ((Google.ProtocolBuffers.Descriptors.FieldDescriptor)field).MessageType;
#endif
break;
}
@ -468,10 +496,16 @@ namespace Google.ProtocolBuffers {
// 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
// field name and other useful info in the exception.
throw new ArgumentException("Wrong object type used with protocol message reflection. "
+ "Message type \"" + field.ContainingType.FullName
+ "\", field \"" + (field.IsExtension ? field.FullName : field.Name)
+ "\", value was type \"" + value.GetType().Name + "\".");
string message = "Wrong object type used with protocol message reflection.";
#if !LITE
Google.ProtocolBuffers.Descriptors.FieldDescriptor fieldinfo = field as Google.ProtocolBuffers.Descriptors.FieldDescriptor;
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);
}
}
}

@ -1,4 +1,5 @@
using System;
using Google.ProtocolBuffers.Descriptors;
namespace Google.ProtocolBuffers {
@ -7,4 +8,111 @@ namespace Google.ProtocolBuffers {
object ContainingType { 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;
}
}
}
}

@ -90,6 +90,7 @@
<Compile Include="Descriptors\PackageDescriptor.cs" />
<Compile Include="Descriptors\ServiceDescriptor.cs" />
<Compile Include="DynamicMessage.cs" />
<Compile Include="EnumLite.cs" />
<Compile Include="ExtendableBuilder.cs" />
<Compile Include="ExtendableMessage.cs" />
<Compile Include="ExtensionInfo.cs">

@ -46,6 +46,8 @@
<ItemGroup>
<Reference Include="mscorlib" />
<Reference Include="System" />
<Reference Include="System.Data" />
<Reference Include="System.Xml" />
</ItemGroup>
<ItemGroup>
</ItemGroup>
@ -55,7 +57,17 @@
<ItemGroup>
<Compile Include="AbstractBuilderLite.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="GeneratedMessageLite.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="ByteString.cs" />
<Compile Include="CodedInputStream.cs" />
@ -66,6 +78,7 @@
<SubType>Code</SubType>
</Compile>
<Compile Include="InvalidProtocolBufferException.cs" />
<Compile Include="ThrowHelper.cs" />
<Compile Include="UninitializedMessageException.cs" />
<Compile Include="WireFormat.cs" />
</ItemGroup>

@ -54,9 +54,13 @@
<Reference Include="System.Xml" />
</ItemGroup>
<ItemGroup>
<Compile Include="..\..\tmp\UnitTestLiteProtoFile.cs">
<Link>UnitTestLiteProtoFile.cs</Link>
</Compile>
<Compile Include="..\ProtocolBuffers.Test\Properties\AssemblyInfo.cs">
<Link>Properties\AssemblyInfo.cs</Link>
</Compile>
<Compile Include="Todo.cs" />
<None Include="TestProtos\UnittestLite.cs" />
<None Include="TestProtos\UnittestLiteImportsNonlite.cs" />
</ItemGroup>

Loading…
Cancel
Save