Changed fixed size methods to return unsigned integers. Finished FieldSet. Introduced mapping from FieldType to WireType and MappedType.

pull/288/head
Jon Skeet 17 years ago
parent 800f65e209
commit c0daf10724
  1. 8
      csharp/ProtocolBuffers.Test/CodedInputStreamTest.cs
  2. 10
      csharp/ProtocolBuffers.Test/CodedOutputStreamTest.cs
  3. 1
      csharp/ProtocolBuffers.Test/ProtocolBuffers.Test.csproj
  4. 20
      csharp/ProtocolBuffers.Test/WireFormatTest.cs
  5. 6
      csharp/ProtocolBuffers/AbstractBuilder.cs
  6. 6
      csharp/ProtocolBuffers/Autogenerated.cs
  7. 83
      csharp/ProtocolBuffers/CodedInputStream.cs
  8. 14
      csharp/ProtocolBuffers/CodedOutputStream.cs
  9. 3
      csharp/ProtocolBuffers/Descriptors/EnumDescriptor.cs
  10. 8
      csharp/ProtocolBuffers/Descriptors/EnumValueDescriptor.cs
  11. 36
      csharp/ProtocolBuffers/Descriptors/FieldDescriptor.cs
  12. 21
      csharp/ProtocolBuffers/Descriptors/FieldMappingAttribute.cs
  13. 40
      csharp/ProtocolBuffers/Descriptors/FieldType.cs
  14. 4
      csharp/ProtocolBuffers/Descriptors/FileDescriptor.cs
  15. 8
      csharp/ProtocolBuffers/Descriptors/MessageDescriptor.cs
  16. 2
      csharp/ProtocolBuffers/FieldAccess/FieldAccessorTable.cs
  17. 249
      csharp/ProtocolBuffers/FieldSet.cs
  18. 12
      csharp/ProtocolBuffers/GeneratedBuilder.cs
  19. 8
      csharp/ProtocolBuffers/IBuilder.cs
  20. 2
      csharp/ProtocolBuffers/ProtocolBuffers.csproj
  21. 24
      csharp/ProtocolBuffers/UnknownField.cs
  22. 38
      csharp/ProtocolBuffers/WireFormat.cs

@ -118,7 +118,7 @@ namespace Google.ProtocolBuffers {
/// Parses the given bytes using ReadRawLittleEndian32() and checks
/// that the result matches the given value.
/// </summary>
private static void AssertReadLittleEndian32(byte[] data, int value) {
private static void AssertReadLittleEndian32(byte[] data, uint value) {
CodedInputStream input = CodedInputStream.CreateInstance(data);
Assert.AreEqual(value, input.ReadRawLittleEndian32());
@ -134,7 +134,7 @@ namespace Google.ProtocolBuffers {
/// Parses the given bytes using ReadRawLittleEndian64() and checks
/// that the result matches the given value.
/// </summary>
private static void AssertReadLittleEndian64(byte[] data, long value) {
private static void AssertReadLittleEndian64(byte[] data, ulong value) {
CodedInputStream input = CodedInputStream.CreateInstance(data);
Assert.AreEqual(value, input.ReadRawLittleEndian64());
@ -149,12 +149,12 @@ namespace Google.ProtocolBuffers {
[Test]
public void ReadLittleEndian() {
AssertReadLittleEndian32(Bytes(0x78, 0x56, 0x34, 0x12), 0x12345678);
AssertReadLittleEndian32(Bytes(0xf0, 0xde, 0xbc, 0x9a), unchecked((int)0x9abcdef0));
AssertReadLittleEndian32(Bytes(0xf0, 0xde, 0xbc, 0x9a), 0x9abcdef0);
AssertReadLittleEndian64(Bytes(0xf0, 0xde, 0xbc, 0x9a, 0x78, 0x56, 0x34, 0x12),
0x123456789abcdef0L);
AssertReadLittleEndian64(
Bytes(0x78, 0x56, 0x34, 0x12, 0xf0, 0xde, 0xbc, 0x9a), unchecked((long)0x9abcdef012345678L));
Bytes(0x78, 0x56, 0x34, 0x12, 0xf0, 0xde, 0xbc, 0x9a), 0x9abcdef012345678UL);
}
[Test]

@ -106,7 +106,7 @@ namespace Google.ProtocolBuffers {
AssertWriteVarint(
Bytes(0x80, 0xe6, 0xeb, 0x9c, 0xc3, 0xc9, 0xa4, 0x49),
(0x00 << 0) | (0x66 << 7) | (0x6b << 14) | (0x1c << 21) |
(0x43L << 28) | (0x49L << 35) | (0x24L << 42) | (0x49L << 49));
(0x43UL << 28) | (0x49L << 35) | (0x24UL << 42) | (0x49UL << 49));
// 11964378330978735131
AssertWriteVarint(
Bytes(0x9b, 0xa8, 0xf9, 0xc2, 0xbb, 0xd6, 0x80, 0x85, 0xa6, 0x01),
@ -120,7 +120,7 @@ namespace Google.ProtocolBuffers {
/// Parses the given bytes using WriteRawLittleEndian32() and checks
/// that the result matches the given value.
/// </summary>
private static void AssertWriteLittleEndian32(byte[] data, int value) {
private static void AssertWriteLittleEndian32(byte[] data, uint value) {
MemoryStream rawOutput = new MemoryStream();
CodedOutputStream output = CodedOutputStream.CreateInstance(rawOutput);
output.WriteRawLittleEndian32(value);
@ -141,7 +141,7 @@ namespace Google.ProtocolBuffers {
/// Parses the given bytes using WriteRawLittleEndian64() and checks
/// that the result matches the given value.
/// </summary>
private static void AssertWriteLittleEndian64(byte[] data, long value) {
private static void AssertWriteLittleEndian64(byte[] data, ulong value) {
MemoryStream rawOutput = new MemoryStream();
CodedOutputStream output = CodedOutputStream.CreateInstance(rawOutput);
output.WriteRawLittleEndian64(value);
@ -164,14 +164,14 @@ namespace Google.ProtocolBuffers {
[Test]
public void WriteLittleEndian() {
AssertWriteLittleEndian32(Bytes(0x78, 0x56, 0x34, 0x12), 0x12345678);
AssertWriteLittleEndian32(Bytes(0xf0, 0xde, 0xbc, 0x9a), unchecked((int)0x9abcdef0));
AssertWriteLittleEndian32(Bytes(0xf0, 0xde, 0xbc, 0x9a), 0x9abcdef0);
AssertWriteLittleEndian64(
Bytes(0xf0, 0xde, 0xbc, 0x9a, 0x78, 0x56, 0x34, 0x12),
0x123456789abcdef0L);
AssertWriteLittleEndian64(
Bytes(0x78, 0x56, 0x34, 0x12, 0xf0, 0xde, 0xbc, 0x9a),
unchecked((long)0x9abcdef012345678L));
0x9abcdef012345678UL);
}
/* TODO(jonskeet): Put this back when we've got the rest working!

@ -48,6 +48,7 @@
<Compile Include="CodedInputStreamTest.cs" />
<Compile Include="CodedOutputStreamTest.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="WireFormatTest.cs" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\ProtocolBuffers\ProtocolBuffers.csproj">

@ -0,0 +1,20 @@
using System;
using System.Collections.Generic;
using System.Text;
using NUnit.Framework;
using Google.ProtocolBuffers.Descriptors;
namespace Google.ProtocolBuffers {
[TestFixture]
public class WireFormatTest {
[Test]
public void FieldTypeToWireTypeMapping() {
// Just test a few values
Assert.AreEqual(WireFormat.WireType.Fixed64, WireFormat.FieldTypeToWireFormatMap[FieldType.SFixed64]);
Assert.AreEqual(WireFormat.WireType.LengthDelimited, WireFormat.FieldTypeToWireFormatMap[FieldType.String]);
Assert.AreEqual(WireFormat.WireType.LengthDelimited, WireFormat.FieldTypeToWireFormatMap[FieldType.Message]);
}
}
}

@ -25,7 +25,7 @@ namespace Google.ProtocolBuffers {
protected abstract IMessage BuildPartialImpl();
protected abstract IBuilder CloneImpl();
protected abstract IMessage DefaultInstanceForTypeImpl { get; }
protected abstract IBuilder NewBuilderForFieldImpl(FieldDescriptor field);
protected abstract IBuilder CreateBuilderForFieldImpl(FieldDescriptor field);
protected abstract IBuilder ClearFieldImpl(FieldDescriptor field);
protected abstract IBuilder AddRepeatedFieldImpl(FieldDescriptor field, object value);
#endregion
@ -47,8 +47,8 @@ namespace Google.ProtocolBuffers {
get { return DefaultInstanceForTypeImpl; }
}
IBuilder IBuilder.NewBuilderForField(FieldDescriptor field) {
return NewBuilderForFieldImpl(field);
IBuilder IBuilder.CreateBuilderForField(FieldDescriptor field) {
return CreateBuilderForFieldImpl(field);
}
IBuilder IBuilder.ClearField(FieldDescriptor field) {

@ -5,5 +5,11 @@ namespace Google.ProtocolBuffers {
public class MessageOptions {
public bool IsMessageSetWireFormat;
}
public class EnumValueDescriptorProto {
}
public class FieldDescriptorProto {
}
}
}

@ -142,7 +142,7 @@ namespace Google.ProtocolBuffers {
/// Read a double field from the stream.
/// </summary>
public double ReadDouble() {
return BitConverter.Int64BitsToDouble(ReadRawLittleEndian64());
return BitConverter.Int64BitsToDouble((long) ReadRawLittleEndian64());
}
/// <summary>
@ -178,14 +178,14 @@ namespace Google.ProtocolBuffers {
/// <summary>
/// Read a fixed64 field from the stream.
/// </summary>
public long ReadFixed64() {
public ulong ReadFixed64() {
return ReadRawLittleEndian64();
}
/// <summary>
/// Read a fixed32 field from the stream.
/// </summary>
public int ReadFixed32() {
public uint ReadFixed32() {
return ReadRawLittleEndian32();
}
@ -293,14 +293,14 @@ namespace Google.ProtocolBuffers {
/// Reads an sfixed32 field value from the stream.
/// </summary>
public int ReadSFixed32() {
return ReadRawLittleEndian32();
return (int) ReadRawLittleEndian32();
}
/// <summary>
/// Reads an sfixed64 field value from the stream.
/// </summary>
public long ReadSFixed64() {
return ReadRawLittleEndian64();
return (long) ReadRawLittleEndian64();
}
/// <summary>
@ -410,26 +410,26 @@ namespace Google.ProtocolBuffers {
/// <summary>
/// Read a 32-bit little-endian integer from the stream.
/// </summary>
public int ReadRawLittleEndian32() {
byte b1 = ReadRawByte();
byte b2 = ReadRawByte();
byte b3 = ReadRawByte();
byte b4 = ReadRawByte();
public uint ReadRawLittleEndian32() {
uint b1 = ReadRawByte();
uint b2 = ReadRawByte();
uint b3 = ReadRawByte();
uint b4 = ReadRawByte();
return b1 | (b2 << 8) | (b3 << 16) | (b4 << 24);
}
/// <summary>
/// Read a 64-bit little-endian integer from the stream.
/// </summary>
public long ReadRawLittleEndian64() {
long b1 = ReadRawByte();
long b2 = ReadRawByte();
long b3 = ReadRawByte();
long b4 = ReadRawByte();
long b5 = ReadRawByte();
long b6 = ReadRawByte();
long b7 = ReadRawByte();
long b8 = ReadRawByte();
public ulong ReadRawLittleEndian64() {
ulong b1 = ReadRawByte();
ulong b2 = ReadRawByte();
ulong b3 = ReadRawByte();
ulong b4 = ReadRawByte();
ulong b5 = ReadRawByte();
ulong b6 = ReadRawByte();
ulong b7 = ReadRawByte();
ulong b8 = ReadRawByte();
return b1 | (b2 << 8) | (b3 << 16) | (b4 << 24)
| (b5 << 32) | (b6 << 40) | (b7 << 48) | (b8 << 56);
}
@ -705,6 +705,51 @@ namespace Google.ProtocolBuffers {
}
}
/// <summary>
/// Reads and discards a single field, given its tag value.
/// </summary>
/// <returns>false if the tag is an end-group tag, in which case
/// nothing is skipped. Otherwise, returns true.</returns>
public bool SkipField(uint tag) {
switch (WireFormat.GetTagWireType(tag)) {
case WireFormat.WireType.Varint:
ReadInt32();
return true;
case WireFormat.WireType.Fixed64:
ReadRawLittleEndian64();
return true;
case WireFormat.WireType.LengthDelimited:
SkipRawBytes((int) ReadRawVarint32());
return true;
case WireFormat.WireType.StartGroup:
SkipMessage();
CheckLastTagWas(
WireFormat.MakeTag(WireFormat.GetTagFieldNumber(tag),
WireFormat.WireType.EndGroup));
return true;
case WireFormat.WireType.EndGroup:
return false;
case WireFormat.WireType.Fixed32:
ReadRawLittleEndian32();
return true;
default:
throw InvalidProtocolBufferException.InvalidWireType();
}
}
/// <summary>
/// Reads and discards an entire message. This will read either until EOF
/// or until an endgroup tag, whichever comes first.
/// </summary>
public void SkipMessage() {
while (true) {
uint tag = ReadTag();
if (tag == 0 || !SkipField(tag)) {
return;
}
}
}
/// <summary>
/// Reads and discards <paramref name="size"/> bytes.
/// </summary>

@ -99,7 +99,7 @@ namespace Google.ProtocolBuffers {
/// </summary>
public void WriteDouble(int fieldNumber, double value) {
WriteTag(fieldNumber, WireFormat.WireType.Fixed64);
WriteRawLittleEndian64(BitConverter.DoubleToInt64Bits(value));
WriteRawLittleEndian64((ulong)BitConverter.DoubleToInt64Bits(value));
}
/// <summary>
@ -143,7 +143,7 @@ namespace Google.ProtocolBuffers {
/// <summary>
/// Writes a fixed64 field value, including tag, to the stream.
/// </summary>
public void WriteFixed64(int fieldNumber, long value) {
public void WriteFixed64(int fieldNumber, ulong value) {
WriteTag(fieldNumber, WireFormat.WireType.Fixed64);
WriteRawLittleEndian64(value);
}
@ -151,7 +151,7 @@ namespace Google.ProtocolBuffers {
/// <summary>
/// Writes a fixed32 field value, including tag, to the stream.
/// </summary>
public void WriteFixed32(int fieldNumber, int value) {
public void WriteFixed32(int fieldNumber, uint value) {
WriteTag(fieldNumber, WireFormat.WireType.Fixed32);
WriteRawLittleEndian32(value);
}
@ -259,8 +259,8 @@ namespace Google.ProtocolBuffers {
case FieldType.Int64: WriteInt64(fieldNumber, (long)value); break;
case FieldType.UInt64: WriteUInt64(fieldNumber, (ulong)value); break;
case FieldType.Int32: WriteInt32(fieldNumber, (int)value); break;
case FieldType.Fixed64: WriteFixed64(fieldNumber, (long)value); break;
case FieldType.Fixed32: WriteFixed32(fieldNumber, (int)value); break;
case FieldType.Fixed64: WriteFixed64(fieldNumber, (ulong)value); break;
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;
@ -310,14 +310,14 @@ namespace Google.ProtocolBuffers {
}
}
public void WriteRawLittleEndian32(int value) {
public void WriteRawLittleEndian32(uint value) {
WriteRawByte((byte)value);
WriteRawByte((byte)(value >> 8));
WriteRawByte((byte)(value >> 16));
WriteRawByte((byte)(value >> 24));
}
public void WriteRawLittleEndian64(long value) {
public void WriteRawLittleEndian64(ulong value) {
WriteRawByte((byte)value);
WriteRawByte((byte)(value >> 8));
WriteRawByte((byte)(value >> 16));

@ -1,5 +1,8 @@

namespace Google.ProtocolBuffers.Descriptors {
public class EnumDescriptor {
internal EnumValueDescriptor FindValueByNumber(int rawValue) {
throw new System.NotImplementedException();
}
}
}

@ -2,6 +2,14 @@
namespace Google.ProtocolBuffers.Descriptors {
public class EnumValueDescriptor {
internal EnumValueDescriptor(DescriptorProtos.EnumValueDescriptorProto proto,
FileDescriptor file,
EnumDescriptor parent,
int index) {
enumDescriptor = parent;
}
private EnumDescriptor enumDescriptor;
public int Number {

@ -1,9 +1,19 @@

using System;
using System;
using System.Collections.Generic;
using System.Reflection;
using Google.ProtocolBuffers.Collections;
namespace Google.ProtocolBuffers.Descriptors {
public class FieldDescriptor {
private FieldDescriptor(DescriptorProtos.FieldDescriptorProto proto,
FileDescriptor file,
MessageDescriptor parent,
int index,
bool isExtension) {
enumType = null;
}
private EnumDescriptor enumType;
public bool IsRequired {
@ -47,14 +57,28 @@ namespace Google.ProtocolBuffers.Descriptors {
/// this will always be an empty list. For message fields it will
/// always be null. For singular values, it will depend on the descriptor.
/// </summary>
public object DefaultValue
{
public object DefaultValue {
get { throw new NotImplementedException(); }
}
public string Name
{
public string Name {
get { throw new NotImplementedException(); }
}
/// <summary>
/// Immutable mapping from field type to mapped type. Built using the attributes on
/// FieldType values.
/// </summary>
public static readonly IDictionary<FieldType, MappedType> FieldTypeToWireFormatMap = MapFieldTypes();
private static IDictionary<FieldType, MappedType> MapFieldTypes() {
var map = new Dictionary<FieldType, MappedType>();
foreach (FieldInfo field in typeof(FieldType).GetFields(BindingFlags.Static | BindingFlags.Public)) {
FieldType fieldType = (FieldType)field.GetValue(null);
FieldMappingAttribute mapping = (FieldMappingAttribute)field.GetCustomAttributes(typeof(FieldMappingAttribute), false)[0];
map[fieldType] = mapping.MappedType;
}
return Dictionaries.AsReadOnly(map);
}
}
}

@ -0,0 +1,21 @@
using System;
using System.Collections.Generic;
using System.Text;
namespace Google.ProtocolBuffers.Descriptors {
/// <summary>
/// Defined specifically for the <see cref="FieldType" /> enumeration,
/// this allows each field type to specify the mapped type and wire type.
/// </summary>
[AttributeUsage(AttributeTargets.Field)]
internal class FieldMappingAttribute : Attribute {
internal FieldMappingAttribute(MappedType mappedType, WireFormat.WireType wireType) {
MappedType = mappedType;
WireType = wireType;
}
internal MappedType MappedType { get; private set; }
internal WireFormat.WireType WireType { get; private set; }
}
}

@ -1,23 +1,27 @@

namespace Google.ProtocolBuffers.Descriptors {
/// <summary>
/// Enumeration of all the possible field types. The odd formatting is to make it very clear
/// which attribute applies to which value, while maintaining a compact format.
/// </summary>
public enum FieldType {
Double,
Float,
Int64,
UInt64,
Int32,
Fixed64,
Fixed32,
Bool,
String,
Group,
Message,
Bytes,
UInt32,
SFixed32,
SFixed64,
SInt32,
SInt64,
Enum
[FieldMapping(MappedType.Double, WireFormat.WireType.Fixed64)] Double,
[FieldMapping(MappedType.Single, WireFormat.WireType.Fixed32)] Float,
[FieldMapping(MappedType.Int64, WireFormat.WireType.Varint)] Int64,
[FieldMapping(MappedType.UInt64, WireFormat.WireType.Varint)] UInt64,
[FieldMapping(MappedType.Int32, WireFormat.WireType.Varint)] Int32,
[FieldMapping(MappedType.UInt64, WireFormat.WireType.Fixed64)] Fixed64,
[FieldMapping(MappedType.UInt32, WireFormat.WireType.Fixed32)] Fixed32,
[FieldMapping(MappedType.Boolean, WireFormat.WireType.Varint)] Bool,
[FieldMapping(MappedType.String, WireFormat.WireType.LengthDelimited)] String,
[FieldMapping(MappedType.Message, WireFormat.WireType.StartGroup)] Group,
[FieldMapping(MappedType.Message, WireFormat.WireType.LengthDelimited)] Message,
[FieldMapping(MappedType.ByteString, WireFormat.WireType.LengthDelimited)] Bytes,
[FieldMapping(MappedType.UInt32, WireFormat.WireType.Varint)] UInt32,
[FieldMapping(MappedType.Int32, WireFormat.WireType.Fixed32)] SFixed32,
[FieldMapping(MappedType.Int64, WireFormat.WireType.Fixed64)] SFixed64,
[FieldMapping(MappedType.Int32, WireFormat.WireType.Varint)] SInt32,
[FieldMapping(MappedType.Int64, WireFormat.WireType.Varint)] SInt64,
[FieldMapping(MappedType.Enum, WireFormat.WireType.Varint)] Enum
}
}

@ -0,0 +1,4 @@
namespace Google.ProtocolBuffers.Descriptors {
class FileDescriptor {
}
}

@ -6,5 +6,13 @@ namespace Google.ProtocolBuffers.Descriptors {
public IList<FieldDescriptor> Fields;
public DescriptorProtos.MessageOptions Options;
public string FullName;
internal bool IsExtensionNumber(int fieldNumber) {
throw new System.NotImplementedException();
}
internal FieldDescriptor FindFieldByNumber(int fieldNumber) {
throw new System.NotImplementedException();
}
}
}

@ -1,6 +1,4 @@
using System;
using System.Collections.Generic;
using System.Text;
using Google.ProtocolBuffers.Descriptors;
namespace Google.ProtocolBuffers.FieldAccess {

@ -104,14 +104,195 @@ namespace Google.ProtocolBuffers {
}
// TODO(jonskeet): Should this be in UnknownFieldSet.Builder really?
/// <summary>
/// Like <see cref="MergeFrom(CodedInputStream, UnknownFieldSet.Builder, ExtensionRegistry, IBuilder)" />
/// but parses a single field.
/// </summary>
/// <param name="input">The input to read the field from</param>
/// <param name="unknownFields">The set of unknown fields to add the newly-read field to</param>
/// <param name="extensionRegistry">Registry to use when an extension field is encountered</param>
/// <param name="builder">A builder (???)</param>
/// <param name="tag">The tag, which should already have been read from the input</param>
/// <returns>true unless the tag is an end-group tag</returns>
internal static bool MergeFieldFrom(CodedInputStream input,
UnknownFieldSet.Builder unknownFields,
ExtensionRegistry extensionRegistry,
IBuilder builder,
uint tag) {
throw new NotImplementedException();
MessageDescriptor type = builder.DescriptorForType;
if (type.Options.IsMessageSetWireFormat
&& tag == WireFormat.MessageSetTag.ItemStart) {
MergeMessageSetExtensionFromCodedStream(input, unknownFields, extensionRegistry, builder);
return true;
}
WireFormat.WireType wireType = WireFormat.GetTagWireType(tag);
int fieldNumber = WireFormat.GetTagFieldNumber(tag);
FieldDescriptor field;
IMessage defaultInstance = null;
if (type.IsExtensionNumber(fieldNumber)) {
ExtensionInfo extension = extensionRegistry[type, fieldNumber];
if (extension == null) {
field = null;
} else {
field = extension.Descriptor;
defaultInstance = extension.DefaultInstance;
}
} else {
field = type.FindFieldByNumber(fieldNumber);
}
// Unknown field or wrong wire type. Skip.
if (field == null || wireType != WireFormat.FieldTypeToWireFormatMap[field.FieldType]) {
return unknownFields.MergeFieldFrom(tag, input);
}
object value;
switch (field.FieldType) {
case FieldType.Group:
case FieldType.Message: {
IBuilder subBuilder;
if (defaultInstance != null) {
subBuilder = defaultInstance.CreateBuilderForType();
} else {
subBuilder = builder.CreateBuilderForField(field);
}
if (!field.IsRepeated) {
subBuilder.MergeFrom((IMessage) builder[field]);
}
if (field.FieldType == FieldType.Group) {
input.ReadGroup(field.FieldNumber, subBuilder, extensionRegistry);
} else {
input.ReadMessage(subBuilder, extensionRegistry);
}
value = subBuilder.Build();
break;
}
case FieldType.Enum: {
int rawValue = input.ReadEnum();
value = field.EnumType.FindValueByNumber(rawValue);
// If the number isn't recognized as a valid value for this enum,
// drop it.
if (value == null) {
unknownFields.MergeVarintField(fieldNumber, (ulong) rawValue);
return true;
}
break;
}
default:
value = input.ReadPrimitiveField(field.FieldType);
break;
}
if (field.IsRepeated) {
builder.AddRepeatedField(field, value);
} else {
builder[field] = value;
}
return true;
}
// TODO(jonskeet): Move to UnknownFieldSet.Builder?
/// <summary>
/// Called by MergeFieldFrom to parse a MessageSet extension.
/// </summary>
private static void MergeMessageSetExtensionFromCodedStream(CodedInputStream input,
UnknownFieldSet.Builder unknownFields,
ExtensionRegistry extensionRegistry,
IBuilder builder) {
MessageDescriptor type = builder.DescriptorForType;
// The wire format for MessageSet is:
// message MessageSet {
// repeated group Item = 1 {
// required int32 typeId = 2;
// required bytes message = 3;
// }
// }
// "typeId" is the extension's field number. The extension can only be
// a message type, where "message" contains the encoded bytes of that
// message.
//
// In practice, we will probably never see a MessageSet item in which
// the message appears before the type ID, or where either field does not
// appear exactly once. However, in theory such cases are valid, so we
// should be prepared to accept them.
int typeId = 0;
ByteString rawBytes = null; // If we encounter "message" before "typeId"
IBuilder subBuilder = null;
FieldDescriptor field = null;
while (true) {
uint tag = input.ReadTag();
if (tag == 0) {
break;
}
if (tag == WireFormat.MessageSetTag.TypeID) {
typeId = input.ReadInt32();
// Zero is not a valid type ID.
if (typeId != 0) {
ExtensionInfo extension = extensionRegistry[type, typeId];
if (extension != null) {
field = extension.Descriptor;
subBuilder = extension.DefaultInstance.CreateBuilderForType();
IMessage originalMessage = (IMessage) builder[field];
if (originalMessage != null) {
subBuilder.MergeFrom(originalMessage);
}
if (rawBytes != null) {
// We already encountered the message. Parse it now.
// TODO(jonskeet): Check this is okay. It's subtly different from the Java, as it doesn't create an input stream from rawBytes.
// In fact, why don't we just call MergeFrom(rawBytes)? And what about the extension registry?
subBuilder.MergeFrom(rawBytes.CreateCodedInput());
rawBytes = null;
}
} else {
// Unknown extension number. If we already saw data, put it
// in rawBytes.
if (rawBytes != null) {
unknownFields.MergeField(typeId,
UnknownField.CreateBuilder()
.AddLengthDelimited(rawBytes)
.Build());
rawBytes = null;
}
}
}
} else if (tag == WireFormat.MessageSetTag.Message) {
if (typeId == 0) {
// We haven't seen a type ID yet, so we have to store the raw bytes for now.
rawBytes = input.ReadBytes();
} else if (subBuilder == null) {
// We don't know how to parse this. Ignore it.
unknownFields.MergeField(typeId,
UnknownField.CreateBuilder()
.AddLengthDelimited(input.ReadBytes())
.Build());
} else {
// We already know the type, so we can parse directly from the input
// with no copying. Hooray!
input.ReadMessage(subBuilder, extensionRegistry);
}
} else {
// Unknown tag. Skip it.
if (!input.SkipField(tag)) {
break; // end of group
}
}
}
input.CheckLastTagWas(WireFormat.MessageSetTag.ItemEnd);
if (subBuilder != null) {
builder[field] = subBuilder.Build();
}
}
/// <summary>
/// Clears all fields.
/// </summary>
@ -120,7 +301,7 @@ namespace Google.ProtocolBuffers {
}
/// <summary>
/// <see cref="IMessage.Item(FieldDescriptor)"/>
/// See <see cref="IMessage.Item(FieldDescriptor)"/>
/// </summary>
/// <remarks>
/// If the field is not set, the behaviour when fetching this property varies by field type:
@ -172,7 +353,7 @@ namespace Google.ProtocolBuffers {
}
/// <summary>
/// <see cref="IMessage.Item(FieldDescriptor,int)" />
/// See <see cref="IMessage.Item(FieldDescriptor,int)" />
/// </summary>
internal object this[FieldDescriptor field, int index] {
get {
@ -196,7 +377,7 @@ namespace Google.ProtocolBuffers {
}
/// <summary>
/// <see cref="IBuilder.AddRepeatedField" />
/// See <see cref="IBuilder.AddRepeatedField" />
/// </summary>
/// <param name="field"></param>
/// <param name="value"></param>
@ -214,7 +395,7 @@ namespace Google.ProtocolBuffers {
}
/// <summary>
/// <see cref="IMessage.IsInitialized" />
/// See <see cref="IMessage.IsInitialized" />
/// </summary>
/// <remarks>
/// Since FieldSet itself does not have any way of knowing about
@ -259,14 +440,14 @@ namespace Google.ProtocolBuffers {
}
/// <summary>
/// <see cref="IBuilder.ClearField" />
/// See <see cref="IBuilder.ClearField" />
/// </summary>
public void ClearField(FieldDescriptor field) {
fields.Remove(field);
}
/// <summary>
/// <see cref="IMessage.GetRepeatedFieldCount" />
/// See <see cref="IMessage.GetRepeatedFieldCount" />
/// </summary>
public int GetRepeatedFieldCount(FieldDescriptor field) {
if (!field.IsRepeated) {
@ -276,6 +457,60 @@ namespace Google.ProtocolBuffers {
return ((List<object>) this[field]).Count;
}
/// <summary>
/// Implementation of both <c>MergeFrom</c> methods.
/// </summary>
/// <param name="otherFields"></param>
private void MergeFields(IEnumerable<KeyValuePair<FieldDescriptor, object>> otherFields) {
// 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
// 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;
}
List<object> list = (List<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.CreateBuilderForType()
.MergeFrom(existingMessage)
.MergeFrom((IMessage)entry.Value)
.Build();
this[field] = merged;
} else {
this[field] = entry.Value;
}
}
}
/// <summary>
/// See <see cref="IBuilder.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);
}
/// <summary>
/// Verifies that the given object is of the correct type to be a valid
/// value for the given field.

@ -73,8 +73,8 @@ namespace Google.ProtocolBuffers {
get { return DefaultInstanceForType; }
}
protected override IBuilder NewBuilderForFieldImpl(FieldDescriptor field) {
return NewBuilderForField(field);
protected override IBuilder CreateBuilderForFieldImpl(FieldDescriptor field) {
return CreateBuilderForField(field);
}
protected override IBuilder ClearFieldImpl(FieldDescriptor field) {
@ -91,9 +91,9 @@ namespace Google.ProtocolBuffers {
throw new NotImplementedException();
}
public abstract IMessage<TMessage> Build();
public abstract TMessage Build();
public abstract IMessage<TMessage> BuildPartial();
public abstract TMessage BuildPartial();
public abstract IBuilder<TMessage> Clone();
@ -105,11 +105,11 @@ namespace Google.ProtocolBuffers {
throw new NotImplementedException();
}
public IMessage<TMessage> DefaultInstanceForType {
public TMessage DefaultInstanceForType {
get { throw new NotImplementedException(); }
}
public IBuilder NewBuilderForField(FieldDescriptor field) {
public IBuilder CreateBuilderForField(FieldDescriptor field) {
throw new NotImplementedException();
}

@ -88,7 +88,7 @@ namespace Google.ProtocolBuffers {
IBuilder MergeFrom(CodedInputStream input);
IBuilder MergeFrom(CodedInputStream codedInputStream, ExtensionRegistry extensionRegistry);
IMessage DefaultInstanceForType { get; }
IBuilder NewBuilderForField(FieldDescriptor field);
IBuilder CreateBuilderForField(FieldDescriptor field);
IBuilder ClearField(FieldDescriptor field);
IBuilder AddRepeatedField(FieldDescriptor field, object value);
IBuilder MergeUnknownFields(UnknownFieldSet unknownFields);
@ -136,14 +136,14 @@ namespace Google.ProtocolBuffers {
/// <exception cref="UninitializedMessageException">the message
/// is missing one or more required fields; use BuildPartial to bypass
/// this check</exception>
new IMessage<T> Build();
new T Build();
/// <summary>
/// Like Build(), but does not throw an exception if the message is missing
/// required fields. Instead, a partial message is returned.
/// </summary>
/// <returns></returns>
new IMessage<T> BuildPartial();
new T BuildPartial();
/// <summary>
/// Clones this builder.
@ -184,7 +184,7 @@ namespace Google.ProtocolBuffers {
/// Get's the message's type's default instance.
/// <see cref="IMessage{T}.DefaultInstanceForType" />
/// </summary>
new IMessage<T> DefaultInstanceForType { get; }
new T DefaultInstanceForType { get; }
/// <summary>
/// Create a builder for messages of the appropriate type for the given field.

@ -48,7 +48,9 @@
<Compile Include="Descriptors\EnumDescriptor.cs" />
<Compile Include="Descriptors\EnumValueDescriptor.cs" />
<Compile Include="Descriptors\FieldDescriptor.cs" />
<Compile Include="Descriptors\FieldMappingAttribute.cs" />
<Compile Include="Descriptors\FieldType.cs" />
<Compile Include="Descriptors\FileDescriptor.cs" />
<Compile Include="Descriptors\MappedType.cs" />
<Compile Include="Descriptors\MessageDescriptor.cs" />
<Compile Include="ExtensionInfo.cs" />

@ -24,14 +24,14 @@ namespace Google.ProtocolBuffers {
private static readonly UnknownField defaultInstance = CreateBuilder().Build();
private readonly ReadOnlyCollection<ulong> varintList;
private readonly ReadOnlyCollection<int> fixed32List;
private readonly ReadOnlyCollection<long> fixed64List;
private readonly ReadOnlyCollection<uint> fixed32List;
private readonly ReadOnlyCollection<ulong> fixed64List;
private readonly ReadOnlyCollection<ByteString> lengthDelimitedList;
private readonly ReadOnlyCollection<UnknownFieldSet> groupList;
private UnknownField(ReadOnlyCollection<ulong> varintList,
ReadOnlyCollection<int> fixed32List,
ReadOnlyCollection<long> fixed64List,
ReadOnlyCollection<uint> fixed32List,
ReadOnlyCollection<ulong> fixed64List,
ReadOnlyCollection<ByteString> lengthDelimitedList,
ReadOnlyCollection<UnknownFieldSet> groupList) {
this.varintList = varintList;
@ -55,14 +55,14 @@ namespace Google.ProtocolBuffers {
/// <summary>
/// The list of fixed32 values for this field.
/// </summary>
public IList<int> Fixed32List {
public IList<uint> Fixed32List {
get { return fixed32List; }
}
/// <summary>
/// The list of fixed64 values for this field.
/// </summary>
public IList<long> Fixed64List {
public IList<ulong> Fixed64List {
get { return fixed64List; }
}
@ -104,10 +104,10 @@ namespace Google.ProtocolBuffers {
foreach (ulong value in varintList) {
output.WriteUInt64(fieldNumber, value);
}
foreach (int value in fixed32List) {
foreach (uint value in fixed32List) {
output.WriteFixed32(fieldNumber, value);
}
foreach (long value in fixed64List) {
foreach (ulong value in fixed64List) {
output.WriteFixed64(fieldNumber, value);
}
foreach (ByteString value in lengthDelimitedList) {
@ -172,8 +172,8 @@ namespace Google.ProtocolBuffers {
public class Builder {
private List<ulong> varintList;
private List<int> fixed32List;
private List<long> fixed64List;
private List<uint> fixed32List;
private List<ulong> fixed64List;
private List<ByteString> lengthDelimitedList;
private List<UnknownFieldSet> groupList;
@ -246,7 +246,7 @@ namespace Google.ProtocolBuffers {
/// <summary>
/// Adds a fixed32 value.
/// </summary>
public Builder AddFixed32(int value) {
public Builder AddFixed32(uint value) {
fixed32List = Add(fixed32List, value);
return this;
}
@ -254,7 +254,7 @@ namespace Google.ProtocolBuffers {
/// <summary>
/// Adds a fixed64 value.
/// </summary>
public Builder AddFixed64(long value) {
public Builder AddFixed64(ulong value) {
fixed64List = Add(fixed64List, value);
return this;
}

@ -13,7 +13,21 @@
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
using System.Reflection;
using Google.ProtocolBuffers.Descriptors;
using System.Collections.Generic;
using Google.ProtocolBuffers.Collections;
namespace Google.ProtocolBuffers {
/// <summary>
/// This class is used internally by the Protocol Buffer Library and generated
/// message implementations. It is public only for the sake of those generated
/// messages. Others should not use this class directly.
/// <para>
/// This class contains constants and helper functions useful for dealing with
/// the Protocol Buffer wire format.
/// </para>
/// </summary>
public class WireFormat {
public enum WireType : uint {
Varint = 0,
@ -30,6 +44,13 @@ namespace Google.ProtocolBuffers {
internal const int Message = 3;
}
internal class MessageSetTag {
internal static readonly uint ItemStart = MakeTag(MessageSetField.Item, WireType.StartGroup);
internal static readonly uint ItemEnd = MakeTag(MessageSetField.Item, WireType.EndGroup);
internal static readonly uint TypeID = MakeTag(MessageSetField.TypeID, WireType.Varint);
internal static readonly uint Message = MakeTag(MessageSetField.Message, WireType.LengthDelimited);
}
private const int TagTypeBits = 3;
private const uint TagTypeMask = (1 << TagTypeBits) - 1;
@ -49,9 +70,26 @@ namespace Google.ProtocolBuffers {
/// <summary>
/// Makes a tag value given a field number and wire type.
/// TODO(jonskeet): Should we just have a Tag structure?
/// </summary>
public static uint MakeTag(int fieldNumber, WireType wireType) {
return (uint) (fieldNumber << TagTypeBits) | (uint) wireType;
}
/// <summary>
/// Immutable mapping from field type to wire type. Built using the attributes on
/// FieldType values.
/// </summary>
public static readonly IDictionary<FieldType, WireType> FieldTypeToWireFormatMap = MapFieldTypes();
private static IDictionary<FieldType, WireType> MapFieldTypes() {
var map = new Dictionary<FieldType, WireType>();
foreach (FieldInfo field in typeof(FieldType).GetFields(BindingFlags.Static | BindingFlags.Public)) {
FieldType fieldType = (FieldType) field.GetValue(null);
FieldMappingAttribute mapping = (FieldMappingAttribute)field.GetCustomAttributes(typeof(FieldMappingAttribute), false)[0];
map[fieldType] = mapping.WireType;
}
return Dictionaries.AsReadOnly(map);
}
}
}

Loading…
Cancel
Save