浏览代码

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

Jon Skeet 17 年之前
父节点
当前提交
c0daf10724

+ 4 - 4
csharp/ProtocolBuffers.Test/CodedInputStreamTest.cs

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

+ 5 - 5
csharp/ProtocolBuffers.Test/CodedOutputStreamTest.cs

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

+ 1 - 0
csharp/ProtocolBuffers.Test/ProtocolBuffers.Test.csproj

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

+ 20 - 0
csharp/ProtocolBuffers.Test/WireFormatTest.cs

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

+ 3 - 3
csharp/ProtocolBuffers/AbstractBuilder.cs

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

+ 6 - 0
csharp/ProtocolBuffers/Autogenerated.cs

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

+ 64 - 19
csharp/ProtocolBuffers/CodedInputStream.cs

@@ -142,7 +142,7 @@ namespace Google.ProtocolBuffers {
     /// Read a double field from the stream.
     /// Read a double field from the stream.
     /// </summary>
     /// </summary>
     public double ReadDouble() {
     public double ReadDouble() {
-      return BitConverter.Int64BitsToDouble(ReadRawLittleEndian64());
+      return BitConverter.Int64BitsToDouble((long) ReadRawLittleEndian64());
     }
     }
 
 
     /// <summary>
     /// <summary>
@@ -178,14 +178,14 @@ namespace Google.ProtocolBuffers {
     /// <summary>
     /// <summary>
     /// Read a fixed64 field from the stream.
     /// Read a fixed64 field from the stream.
     /// </summary>
     /// </summary>
-    public long ReadFixed64() {
+    public ulong ReadFixed64() {
       return ReadRawLittleEndian64();
       return ReadRawLittleEndian64();
     }
     }
 
 
     /// <summary>
     /// <summary>
     /// Read a fixed32 field from the stream.
     /// Read a fixed32 field from the stream.
     /// </summary>
     /// </summary>
-    public int ReadFixed32() {
+    public uint ReadFixed32() {
       return ReadRawLittleEndian32();
       return ReadRawLittleEndian32();
     }
     }
 
 
@@ -293,14 +293,14 @@ namespace Google.ProtocolBuffers {
     /// Reads an sfixed32 field value from the stream.
     /// Reads an sfixed32 field value from the stream.
     /// </summary>   
     /// </summary>   
     public int ReadSFixed32() {
     public int ReadSFixed32() {
-      return ReadRawLittleEndian32();
+      return (int) ReadRawLittleEndian32();
     }
     }
 
 
     /// <summary>
     /// <summary>
     /// Reads an sfixed64 field value from the stream.
     /// Reads an sfixed64 field value from the stream.
     /// </summary>   
     /// </summary>   
     public long ReadSFixed64() {
     public long ReadSFixed64() {
-      return ReadRawLittleEndian64();
+      return (long) ReadRawLittleEndian64();
     }
     }
 
 
     /// <summary>
     /// <summary>
@@ -410,26 +410,26 @@ namespace Google.ProtocolBuffers {
     /// <summary>
     /// <summary>
     /// Read a 32-bit little-endian integer from the stream.
     /// Read a 32-bit little-endian integer from the stream.
     /// </summary>
     /// </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);
       return b1 | (b2 << 8) | (b3 << 16) | (b4 << 24);
     }
     }
 
 
     /// <summary>
     /// <summary>
     /// Read a 64-bit little-endian integer from the stream.
     /// Read a 64-bit little-endian integer from the stream.
     /// </summary>
     /// </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)
       return b1 | (b2 << 8) | (b3 << 16) | (b4 << 24)
           | (b5 << 32) | (b6 << 40) | (b7 << 48) | (b8 << 56);
           | (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>
     /// <summary>
     /// Reads and discards <paramref name="size"/> bytes.
     /// Reads and discards <paramref name="size"/> bytes.
     /// </summary>
     /// </summary>

+ 7 - 7
csharp/ProtocolBuffers/CodedOutputStream.cs

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

+ 3 - 0
csharp/ProtocolBuffers/Descriptors/EnumDescriptor.cs

@@ -1,5 +1,8 @@
 
 
 namespace Google.ProtocolBuffers.Descriptors {
 namespace Google.ProtocolBuffers.Descriptors {
   public class EnumDescriptor {
   public class EnumDescriptor {
+    internal EnumValueDescriptor FindValueByNumber(int rawValue) {
+      throw new System.NotImplementedException();
+    }
   }
   }
 }
 }

+ 8 - 0
csharp/ProtocolBuffers/Descriptors/EnumValueDescriptor.cs

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

+ 30 - 6
csharp/ProtocolBuffers/Descriptors/FieldDescriptor.cs

@@ -1,9 +1,19 @@
-
-using System;
+using System;
+using System.Collections.Generic;
+using System.Reflection;
+using Google.ProtocolBuffers.Collections;
 
 
 namespace Google.ProtocolBuffers.Descriptors {
 namespace Google.ProtocolBuffers.Descriptors {
   public class FieldDescriptor {
   public class FieldDescriptor {
 
 
+    private FieldDescriptor(DescriptorProtos.FieldDescriptorProto proto,
+                            FileDescriptor file,
+                            MessageDescriptor parent,
+                            int index,
+                            bool isExtension) {
+      enumType = null;
+    }
+
     private EnumDescriptor enumType;
     private EnumDescriptor enumType;
 
 
     public bool IsRequired {
     public bool IsRequired {
@@ -47,14 +57,28 @@ namespace Google.ProtocolBuffers.Descriptors {
     /// this will always be an empty list. For message fields it will
     /// this will always be an empty list. For message fields it will
     /// always be null. For singular values, it will depend on the descriptor.
     /// always be null. For singular values, it will depend on the descriptor.
     /// </summary>
     /// </summary>
-    public object DefaultValue
-    {
+    public object DefaultValue {
       get { throw new NotImplementedException(); }
       get { throw new NotImplementedException(); }
     }
     }
 
 
-    public string Name
-    {
+    public string Name {
       get { throw new NotImplementedException(); }
       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);
+    }
   }
   }
 }
 }

+ 21 - 0
csharp/ProtocolBuffers/Descriptors/FieldMappingAttribute.cs

@@ -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; }
+  }
+}

+ 22 - 18
csharp/ProtocolBuffers/Descriptors/FieldType.cs

@@ -1,23 +1,27 @@
 
 
 namespace Google.ProtocolBuffers.Descriptors {
 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 {
   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
   }
   }
 }
 }

+ 4 - 0
csharp/ProtocolBuffers/Descriptors/FileDescriptor.cs

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

+ 8 - 0
csharp/ProtocolBuffers/Descriptors/MessageDescriptor.cs

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

+ 0 - 2
csharp/ProtocolBuffers/FieldAccess/FieldAccessorTable.cs

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

+ 242 - 7
csharp/ProtocolBuffers/FieldSet.cs

@@ -104,14 +104,195 @@ namespace Google.ProtocolBuffers {
     }
     }
 
 
     // TODO(jonskeet): Should this be in UnknownFieldSet.Builder really?
     // 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,
     internal static bool MergeFieldFrom(CodedInputStream input,
         UnknownFieldSet.Builder unknownFields,
         UnknownFieldSet.Builder unknownFields,
         ExtensionRegistry extensionRegistry,
         ExtensionRegistry extensionRegistry,
         IBuilder builder,
         IBuilder builder,
         uint tag) {
         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>
     /// <summary>
     /// Clears all fields.
     /// Clears all fields.
     /// </summary>
     /// </summary>
@@ -120,7 +301,7 @@ namespace Google.ProtocolBuffers {
     }
     }
 
 
     /// <summary>
     /// <summary>
-    /// <see cref="IMessage.Item(FieldDescriptor)"/>
+    /// See <see cref="IMessage.Item(FieldDescriptor)"/>
     /// </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:
@@ -172,7 +353,7 @@ namespace Google.ProtocolBuffers {
     }
     }
 
 
     /// <summary>
     /// <summary>
-    /// <see cref="IMessage.Item(FieldDescriptor,int)" />
+    /// See <see cref="IMessage.Item(FieldDescriptor,int)" />
     /// </summary>
     /// </summary>
     internal object this[FieldDescriptor field, int index] {
     internal object this[FieldDescriptor field, int index] {
       get {
       get {
@@ -196,7 +377,7 @@ namespace Google.ProtocolBuffers {
     }
     }
 
 
     /// <summary>
     /// <summary>
-    /// <see cref="IBuilder.AddRepeatedField" />
+    /// See <see cref="IBuilder.AddRepeatedField" />
     /// </summary>
     /// </summary>
     /// <param name="field"></param>
     /// <param name="field"></param>
     /// <param name="value"></param>
     /// <param name="value"></param>
@@ -214,7 +395,7 @@ namespace Google.ProtocolBuffers {
     }
     }
 
 
     /// <summary>
     /// <summary>
-    /// <see cref="IMessage.IsInitialized" />
+    /// See <see cref="IMessage.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
@@ -259,14 +440,14 @@ namespace Google.ProtocolBuffers {
     }
     }
 
 
     /// <summary>
     /// <summary>
-    /// <see cref="IBuilder.ClearField" />
+    /// See <see cref="IBuilder.ClearField" />
     /// </summary>
     /// </summary>
     public void ClearField(FieldDescriptor field) {
     public void ClearField(FieldDescriptor field) {
       fields.Remove(field);
       fields.Remove(field);
     }
     }
 
 
     /// <summary>
     /// <summary>
-    /// <see cref="IMessage.GetRepeatedFieldCount" />
+    /// See <see cref="IMessage.GetRepeatedFieldCount" />
     /// </summary>
     /// </summary>
     public int GetRepeatedFieldCount(FieldDescriptor field) {
     public int GetRepeatedFieldCount(FieldDescriptor field) {
       if (!field.IsRepeated) {
       if (!field.IsRepeated) {
@@ -276,6 +457,60 @@ namespace Google.ProtocolBuffers {
       return ((List<object>) this[field]).Count;
       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>
     /// <summary>
     /// Verifies that the given object is of the correct type to be a valid
     /// Verifies that the given object is of the correct type to be a valid
     /// value for the given field.
     /// value for the given field.

+ 6 - 6
csharp/ProtocolBuffers/GeneratedBuilder.cs

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

+ 4 - 4
csharp/ProtocolBuffers/IBuilder.cs

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

+ 2 - 0
csharp/ProtocolBuffers/ProtocolBuffers.csproj

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

+ 12 - 12
csharp/ProtocolBuffers/UnknownField.cs

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

+ 38 - 0
csharp/ProtocolBuffers/WireFormat.cs

@@ -13,7 +13,21 @@
 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 // See the License for the specific language governing permissions and
 // See the License for the specific language governing permissions and
 // limitations under the License.
 // limitations under the License.
+using System.Reflection;
+using Google.ProtocolBuffers.Descriptors;
+using System.Collections.Generic;
+using Google.ProtocolBuffers.Collections;
 namespace Google.ProtocolBuffers {
 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 class WireFormat {
     public enum WireType : uint {
     public enum WireType : uint {
       Varint = 0,
       Varint = 0,
@@ -30,6 +44,13 @@ namespace Google.ProtocolBuffers {
       internal const int Message = 3;
       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 int TagTypeBits = 3;
     private const uint TagTypeMask = (1 << TagTypeBits) - 1;
     private const uint TagTypeMask = (1 << TagTypeBits) - 1;
 
 
@@ -49,9 +70,26 @@ namespace Google.ProtocolBuffers {
 
 
     /// <summary>
     /// <summary>
     /// Makes a tag value given a field number and wire type.
     /// Makes a tag value given a field number and wire type.
+    /// TODO(jonskeet): Should we just have a Tag structure?
     /// </summary>
     /// </summary>
     public static uint MakeTag(int fieldNumber, WireType wireType) {
     public static uint MakeTag(int fieldNumber, WireType wireType) {
       return (uint) (fieldNumber << TagTypeBits) | (uint) 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);
+    }
   }
   }
 }
 }