瀏覽代碼

Support packed primitive types

Jon Skeet 16 年之前
父節點
當前提交
25a28580a6

二進制
lib/protoc.exe


+ 7 - 0
protos/google/protobuf/descriptor.proto

@@ -252,6 +252,8 @@ message FileOptions {
   }
   optional OptimizeMode optimize_for = 9 [default=CODE_SIZE];
 
+
+
   // The parser stores options it doesn't recognize here. See above.
   repeated UninterpretedOption uninterpreted_option = 999;
 
@@ -298,6 +300,11 @@ message FieldOptions {
 
     STRING_PIECE = 2;
   }
+  // The packed option can be enabled for repeated primitive fields to enable
+  // a more efficient representation on the wire. Rather than repeatedly
+  // writing the tag and type for each element, the entire array is encoded as
+  // a single length-delimited blob.
+  optional bool packed = 2;
 
   // EXPERIMENTAL.  DO NOT USE.
   // For "map" fields, the name of the field in the enclosed type that

+ 38 - 0
protos/google/protobuf/unittest.proto

@@ -458,6 +458,44 @@ message TestExtremeDefaultValues {
   optional string utf8_string = 6 [default = "\341\210\264"];
 }
 
+message TestPackedTypes {
+  repeated    int32 packed_int32    =  90 [packed = true];
+  repeated    int64 packed_int64    =  91 [packed = true];
+  repeated   uint32 packed_uint32   =  92 [packed = true];
+  repeated   uint64 packed_uint64   =  93 [packed = true];
+  repeated   sint32 packed_sint32   =  94 [packed = true];
+  repeated   sint64 packed_sint64   =  95 [packed = true];
+  repeated  fixed32 packed_fixed32  =  96 [packed = true];
+  repeated  fixed64 packed_fixed64  =  97 [packed = true];
+  repeated sfixed32 packed_sfixed32 =  98 [packed = true];
+  repeated sfixed64 packed_sfixed64 =  99 [packed = true];
+  repeated    float packed_float    = 100 [packed = true];
+  repeated   double packed_double   = 101 [packed = true];
+  repeated     bool packed_bool     = 102 [packed = true];
+  repeated ForeignEnum packed_enum  = 103 [packed = true];
+}
+
+message TestPackedExtensions {
+  extensions 1 to max;
+}
+
+extend TestPackedExtensions {
+  repeated    int32 packed_int32_extension    =  90 [packed = true];
+  repeated    int64 packed_int64_extension    =  91 [packed = true];
+  repeated   uint32 packed_uint32_extension   =  92 [packed = true];
+  repeated   uint64 packed_uint64_extension   =  93 [packed = true];
+  repeated   sint32 packed_sint32_extension   =  94 [packed = true];
+  repeated   sint64 packed_sint64_extension   =  95 [packed = true];
+  repeated  fixed32 packed_fixed32_extension  =  96 [packed = true];
+  repeated  fixed64 packed_fixed64_extension  =  97 [packed = true];
+  repeated sfixed32 packed_sfixed32_extension =  98 [packed = true];
+  repeated sfixed64 packed_sfixed64_extension =  99 [packed = true];
+  repeated    float packed_float_extension    = 100 [packed = true];
+  repeated   double packed_double_extension   = 101 [packed = true];
+  repeated     bool packed_bool_extension     = 102 [packed = true];
+  repeated ForeignEnum packed_enum_extension  = 103 [packed = true];
+}
+
 // Test that RPC services work.
 message FooRequest  {}
 message FooResponse {}

+ 75 - 28
src/ProtoBench/BenchmarkSpeedProtoFile.cs

@@ -523,8 +523,10 @@ namespace Google.ProtocolBuffers.ProtoBench {
       if (HasField4) {
         output.WriteString(4, Field4);
       }
-      foreach (ulong element in Field5List) {
-        output.WriteFixed64(5, element);
+      if (field5_.Count > 0) {
+        foreach (ulong element in field5_) {
+          output.WriteFixed64(5, element);
+        }
       }
       if (HasField6) {
         output.WriteInt32(6, Field6);
@@ -677,8 +679,11 @@ namespace Google.ProtocolBuffers.ProtoBench {
         if (HasField4) {
           size += pb::CodedOutputStream.ComputeStringSize(4, Field4);
         }
-        foreach (ulong element in Field5List) {
-          size += pb::CodedOutputStream.ComputeFixed64Size(5, element);
+        {
+          int dataSize = 0;
+          dataSize = 8 * field5_.Count;
+          size += dataSize;
+          size += 1 * field5_.Count;
         }
         if (HasField59) {
           size += pb::CodedOutputStream.ComputeBoolSize(59, Field59);
@@ -3116,8 +3121,10 @@ namespace Google.ProtocolBuffers.ProtoBench {
           if (HasField13) {
             output.WriteString(13, Field13);
           }
-          foreach (string element in Field14List) {
-            output.WriteString(14, element);
+          if (field14_.Count > 0) {
+            foreach (string element in field14_) {
+              output.WriteString(14, element);
+            }
           }
           if (HasField15) {
             output.WriteUInt64(15, Field15);
@@ -3128,8 +3135,10 @@ namespace Google.ProtocolBuffers.ProtoBench {
           if (HasField20) {
             output.WriteInt32(20, Field20);
           }
-          foreach (string element in Field22List) {
-            output.WriteString(22, element);
+          if (field22_.Count > 0) {
+            foreach (string element in field22_) {
+              output.WriteString(22, element);
+            }
           }
           if (HasField24) {
             output.WriteString(24, Field24);
@@ -3149,8 +3158,10 @@ namespace Google.ProtocolBuffers.ProtoBench {
           if (HasField31) {
             output.WriteMessage(31, Field31);
           }
-          foreach (int element in Field73List) {
-            output.WriteInt32(73, element);
+          if (field73_.Count > 0) {
+            foreach (int element in field73_) {
+              output.WriteInt32(73, element);
+            }
           }
           UnknownFields.WriteTo(output);
         }
@@ -3174,8 +3185,13 @@ namespace Google.ProtocolBuffers.ProtoBench {
             if (HasField13) {
               size += pb::CodedOutputStream.ComputeStringSize(13, Field13);
             }
-            foreach (string element in Field14List) {
-              size += pb::CodedOutputStream.ComputeStringSize(14, element);
+            {
+              int dataSize = 0;
+              foreach (string element in Field14List) {
+                dataSize += pb::CodedOutputStream.ComputeStringSizeNoTag(element);
+              }
+              size += dataSize;
+              size += 1 * field14_.Count;
             }
             if (HasField15) {
               size += pb::CodedOutputStream.ComputeUInt64Size(15, Field15);
@@ -3195,11 +3211,21 @@ namespace Google.ProtocolBuffers.ProtoBench {
             if (HasField16) {
               size += pb::CodedOutputStream.ComputeStringSize(16, Field16);
             }
-            foreach (string element in Field22List) {
-              size += pb::CodedOutputStream.ComputeStringSize(22, element);
+            {
+              int dataSize = 0;
+              foreach (string element in Field22List) {
+                dataSize += pb::CodedOutputStream.ComputeStringSizeNoTag(element);
+              }
+              size += dataSize;
+              size += 2 * field22_.Count;
             }
-            foreach (int element in Field73List) {
-              size += pb::CodedOutputStream.ComputeInt32Size(73, element);
+            {
+              int dataSize = 0;
+              foreach (int element in Field73List) {
+                dataSize += pb::CodedOutputStream.ComputeInt32SizeNoTag(element);
+              }
+              size += dataSize;
+              size += 2 * field73_.Count;
             }
             if (HasField20) {
               size += pb::CodedOutputStream.ComputeInt32Size(20, Field20);
@@ -4110,17 +4136,23 @@ namespace Google.ProtocolBuffers.ProtoBench {
       if (HasField109) {
         output.WriteInt32(109, Field109);
       }
-      foreach (string element in Field127List) {
-        output.WriteString(127, element);
+      if (field127_.Count > 0) {
+        foreach (string element in field127_) {
+          output.WriteString(127, element);
+        }
       }
-      foreach (string element in Field128List) {
-        output.WriteString(128, element);
+      if (field128_.Count > 0) {
+        foreach (string element in field128_) {
+          output.WriteString(128, element);
+        }
       }
       if (HasField129) {
         output.WriteInt32(129, Field129);
       }
-      foreach (long element in Field130List) {
-        output.WriteInt64(130, element);
+      if (field130_.Count > 0) {
+        foreach (long element in field130_) {
+          output.WriteInt64(130, element);
+        }
       }
       if (HasField131) {
         output.WriteInt64(131, Field131);
@@ -4240,20 +4272,35 @@ namespace Google.ProtocolBuffers.ProtoBench {
         foreach (global::Google.ProtocolBuffers.ProtoBench.SpeedMessage3.Types.Group1 element in Group1List) {
           size += pb::CodedOutputStream.ComputeGroupSize(10, element);
         }
-        foreach (string element in Field128List) {
-          size += pb::CodedOutputStream.ComputeStringSize(128, element);
+        {
+          int dataSize = 0;
+          foreach (string element in Field128List) {
+            dataSize += pb::CodedOutputStream.ComputeStringSizeNoTag(element);
+          }
+          size += dataSize;
+          size += 2 * field128_.Count;
         }
         if (HasField131) {
           size += pb::CodedOutputStream.ComputeInt64Size(131, Field131);
         }
-        foreach (string element in Field127List) {
-          size += pb::CodedOutputStream.ComputeStringSize(127, element);
+        {
+          int dataSize = 0;
+          foreach (string element in Field127List) {
+            dataSize += pb::CodedOutputStream.ComputeStringSizeNoTag(element);
+          }
+          size += dataSize;
+          size += 2 * field127_.Count;
         }
         if (HasField129) {
           size += pb::CodedOutputStream.ComputeInt32Size(129, Field129);
         }
-        foreach (long element in Field130List) {
-          size += pb::CodedOutputStream.ComputeInt64Size(130, element);
+        {
+          int dataSize = 0;
+          foreach (long element in Field130List) {
+            dataSize += pb::CodedOutputStream.ComputeInt64SizeNoTag(element);
+          }
+          size += dataSize;
+          size += 2 * field130_.Count;
         }
         if (HasField205) {
           size += pb::CodedOutputStream.ComputeBoolSize(205, Field205);

+ 39 - 0
src/ProtoGen/FieldGeneratorBase.cs

@@ -97,6 +97,45 @@ namespace Google.ProtocolBuffers.ProtoGen {
       }
     }
 
+    /// <summary>
+    /// For encodings with fixed sizes, returns that size in bytes.  Otherwise
+    /// returns -1. TODO(jonskeet): Make this less ugly.
+    /// </summary>
+    protected int FixedSize {
+      get {
+        switch (Descriptor.FieldType) {
+          case FieldType.UInt32:
+          case FieldType.UInt64:
+          case FieldType.Int32:
+          case FieldType.Int64:
+          case FieldType.SInt32:
+          case FieldType.SInt64:
+          case FieldType.Enum:
+          case FieldType.Bytes:
+          case FieldType.String:
+          case FieldType.Message:
+          case FieldType.Group:
+            return -1;
+          case FieldType.Float:
+            return WireFormat.FloatSize;
+          case FieldType.SFixed32:
+            return WireFormat.SFixed32Size;
+          case FieldType.Fixed32:
+            return WireFormat.Fixed32Size;
+          case FieldType.Double:
+            return WireFormat.DoubleSize;
+          case FieldType.SFixed64:
+            return WireFormat.SFixed64Size;
+          case FieldType.Fixed64:
+            return WireFormat.Fixed64Size;
+          case FieldType.Bool:
+            return WireFormat.BoolSize;
+          default:
+            throw new InvalidOperationException("Invalid field descriptor type");
+        }
+      }
+    }
+
     protected bool IsNullableType {
       get {
         switch (Descriptor.FieldType) {

+ 1 - 1
src/ProtoGen/MessageGenerator.cs

@@ -391,7 +391,7 @@ namespace Google.ProtocolBuffers.ProtoGen {
       writer.WriteLine("  break;");
       writer.WriteLine("}");
       foreach (FieldDescriptor field in sortedFields) {
-        uint tag = WireFormat.MakeTag(field.FieldNumber, WireFormat.GetWireType(field.FieldType));
+        uint tag = WireFormat.MakeTag(field);
         writer.WriteLine("case {0}: {{", tag);
         writer.Indent();
         SourceGenerators.CreateFieldGenerator(field).GenerateParsingCode(writer);

+ 56 - 7
src/ProtoGen/RepeatedEnumFieldGenerator.cs

@@ -1,6 +1,4 @@
-using System;
-using System.Collections.Generic;
-using System.Text;
+using Google.ProtocolBuffers.DescriptorProtos;
 using Google.ProtocolBuffers.Descriptors;
 
 namespace Google.ProtocolBuffers.ProtoGen {
@@ -11,6 +9,9 @@ namespace Google.ProtocolBuffers.ProtoGen {
     }
 
     public void GenerateMembers(TextGenerator writer) {
+      if (Descriptor.IsPacked && Descriptor.File.Options.OptimizeFor == FileOptions.Types.OptimizeMode.SPEED) {
+        writer.WriteLine("private int {0}MemoizedSerializedSize;", Name);
+      }
       writer.WriteLine("private pbc::PopsicleList<{0}> {1}_ = new pbc::PopsicleList<{0}>();", TypeName, Name);
       writer.WriteLine("public scg::IList<{0}> {1}List {{", TypeName, PropertyName);
       writer.WriteLine("  get {{ return pbc::Lists.AsReadOnly({0}_); }}", Name);
@@ -66,6 +67,15 @@ namespace Google.ProtocolBuffers.ProtoGen {
     }
 
     public void GenerateParsingCode(TextGenerator writer) {
+        // If packed, set up the while loop
+      if (Descriptor.IsPacked) {
+        writer.WriteLine("int length = input.ReadInt32();");
+        writer.WriteLine("int oldLimit = input.PushLimit(length);");
+        writer.WriteLine("while (!input.ReachedLimit) {");
+        writer.Indent();
+      }
+
+      // Read and store the enum
       // TODO(jonskeet): Make a more efficient way of doing this
       writer.WriteLine("int rawValue = input.ReadEnum();");
       writer.WriteLine("if (!global::System.Enum.IsDefined(typeof({0}), rawValue)) {{", TypeName);
@@ -73,17 +83,56 @@ namespace Google.ProtocolBuffers.ProtoGen {
       writer.WriteLine("} else {");
       writer.WriteLine("  Add{0}(({1}) rawValue);", PropertyName, TypeName);
       writer.WriteLine("}");
+
+      if (Descriptor.IsPacked) {
+        writer.Outdent();
+        writer.WriteLine("}");
+        writer.WriteLine("input.PopLimit(oldLimit);");
+      }
     }
 
     public void GenerateSerializationCode(TextGenerator writer) {
-      writer.WriteLine("foreach ({0} element in {1}List) {{", TypeName, PropertyName);
-      writer.WriteLine("  output.WriteEnum({0}, (int) element);", Number);
+      writer.WriteLine("if ({0}_.Count > 0) {{", Name);
+      writer.Indent();
+      if (Descriptor.IsPacked) {
+        writer.WriteLine("output.WriteRawVarint32({0});", WireFormat.MakeTag(Descriptor));
+        writer.WriteLine("output.WriteRawVarint32((uint) {0}MemoizedSerializedSize);", Name);
+        writer.WriteLine("foreach (int element in {0}_) {{", Name);
+        writer.WriteLine("  output.WriteEnumNoTag(element);");
+        writer.WriteLine("}");
+      } else {
+        writer.WriteLine("foreach (int element in {0}_) {{", Name);
+        writer.WriteLine("  output.WriteEnum({0}, element);", Number);
+        writer.WriteLine("}");
+      }
+      writer.Outdent();
       writer.WriteLine("}");
     }
 
     public void GenerateSerializedSizeCode(TextGenerator writer) {
-      writer.WriteLine("foreach ({0} element in {1}List) {{", TypeName, PropertyName);
-      writer.WriteLine("  size += pb::CodedOutputStream.ComputeEnumSize({0}, (int) element);", Number);
+      writer.WriteLine("{");
+      writer.Indent();
+      writer.WriteLine("int dataSize = 0;");
+      writer.WriteLine("if ({0}_.Count > 0) {{", Name);
+      writer.Indent();
+      writer.WriteLine("foreach ({0} element in {1}_) {{", TypeName, Name);
+      writer.WriteLine("  dataSize += pb::CodedOutputStream.ComputeEnumSizeNoTag((int) element);");
+      writer.WriteLine("}");
+      writer.WriteLine("size += dataSize;");
+      int tagSize = CodedOutputStream.ComputeTagSize(Descriptor.FieldNumber);
+      if (Descriptor.IsPacked) {
+        writer.WriteLine("size += {0};", tagSize);
+        writer.WriteLine("size += pb::CodedOutputStream.ComputeRawVarint32Size((uint) dataSize);");
+      } else {
+        writer.WriteLine("size += {0} * {1}_.Count;", tagSize, Name);
+      }
+      writer.Outdent();
+      writer.WriteLine("}");
+      // cache the data size for packed fields.
+      if (Descriptor.IsPacked) {
+        writer.WriteLine("{0}MemoizedSerializedSize = dataSize;", Name);
+      }
+      writer.Outdent();
       writer.WriteLine("}");
     }
   }

+ 51 - 5
src/ProtoGen/RepeatedPrimitiveFieldGenerator.cs

@@ -1,6 +1,7 @@
 using System;
 using System.Collections.Generic;
 using System.Text;
+using Google.ProtocolBuffers.DescriptorProtos;
 using Google.ProtocolBuffers.Descriptors;
 
 namespace Google.ProtocolBuffers.ProtoGen {
@@ -11,6 +12,9 @@ namespace Google.ProtocolBuffers.ProtoGen {
     }
 
     public void GenerateMembers(TextGenerator writer) {
+      if (Descriptor.IsPacked && Descriptor.File.Options.OptimizeFor == FileOptions.Types.OptimizeMode.SPEED) {
+        writer.WriteLine("private int {0}MemoizedSerializedSize;", Name);
+      }
       writer.WriteLine("private pbc::PopsicleList<{0}> {1}_ = new pbc::PopsicleList<{0}>();", TypeName, Name);
       writer.WriteLine("public scg::IList<{0}> {1}List {{", TypeName, PropertyName);
       writer.WriteLine("  get {{ return pbc::Lists.AsReadOnly({0}_); }}", Name);
@@ -68,18 +72,60 @@ namespace Google.ProtocolBuffers.ProtoGen {
     }
 
     public void GenerateParsingCode(TextGenerator writer) {
-      writer.WriteLine("Add{0}(input.Read{1}());", PropertyName, CapitalizedTypeName);
+      if (Descriptor.IsPacked) {
+        writer.WriteLine("int length = input.ReadInt32();");
+        writer.WriteLine("int limit = input.PushLimit(length);");
+        writer.WriteLine("while (!input.ReachedLimit) {");
+        writer.WriteLine("  Add{0}(input.Read{1}());", PropertyName, CapitalizedTypeName);
+        writer.WriteLine("}");
+        writer.WriteLine("input.PopLimit(limit);");
+      } else {
+        writer.WriteLine("Add{0}(input.Read{1}());", PropertyName, CapitalizedTypeName);
+      }
     }
 
     public void GenerateSerializationCode(TextGenerator writer) {
-      writer.WriteLine("foreach ({0} element in {1}List) {{", TypeName, PropertyName);
-      writer.WriteLine("  output.Write{0}({1}, element);", CapitalizedTypeName, Number);
+      writer.WriteLine("if ({0}_.Count > 0) {{", Name);
+      writer.Indent();
+      if (Descriptor.IsPacked) {
+        writer.WriteLine("output.WriteRawVarint32({0});", WireFormat.MakeTag(Descriptor));
+        writer.WriteLine("output.WriteRawVarint32((uint) {0}MemoizedSerializedSize);", Name);
+        writer.WriteLine("foreach ({0} element in {1}_) {{", TypeName, Name);
+        writer.WriteLine("  output.Write{0}NoTag(element);", CapitalizedTypeName);
+        writer.WriteLine("}");
+      } else {
+        writer.WriteLine("foreach ({0} element in {1}_) {{", TypeName, Name);
+        writer.WriteLine("  output.Write{0}({1}, element);", CapitalizedTypeName, Number);
+        writer.WriteLine("}");
+      }
+      writer.Outdent();
       writer.WriteLine("}");
     }
 
     public void GenerateSerializedSizeCode(TextGenerator writer) {
-      writer.WriteLine("foreach ({0} element in {1}List) {{", TypeName, PropertyName);
-      writer.WriteLine("  size += pb::CodedOutputStream.Compute{0}Size({1}, element);", CapitalizedTypeName, Number);
+      writer.WriteLine("{");
+      writer.Indent();
+      writer.WriteLine("int dataSize = 0;");
+      if (FixedSize == -1) {
+        writer.WriteLine("foreach ({0} element in {1}List) {{", TypeName, PropertyName);
+        writer.WriteLine("  dataSize += pb::CodedOutputStream.Compute{0}SizeNoTag(element);", CapitalizedTypeName, Number);
+        writer.WriteLine("}");
+      } else {
+        writer.WriteLine("dataSize = {0} * {1}_.Count;", FixedSize, Name);
+      }
+      writer.WriteLine("size += dataSize;");
+      int tagSize = CodedOutputStream.ComputeTagSize(Descriptor.FieldNumber);
+      if (Descriptor.IsPacked) {
+        writer.WriteLine("size += {0};", tagSize);
+        writer.WriteLine("size += pb::CodedOutputStream.ComputeInt32SizeNoTag(dataSize);");
+      } else {
+        writer.WriteLine("size += {0} * {1}_.Count;", tagSize, Name);
+      }
+      // cache the data size for packed fields.
+      if (Descriptor.IsPacked) {
+        writer.WriteLine("{0}MemoizedSerializedSize = dataSize;", Name);
+      }
+      writer.Outdent();
       writer.WriteLine("}");
     }
   }

+ 14 - 0
src/ProtocolBuffers.Test/AbstractMessageTest.cs

@@ -73,6 +73,20 @@ namespace Google.ProtocolBuffers {
       TestUtil.AssertAllFieldsSet((TestAllTypes) message.WrappedMessage);
     }
 
+    [Test]
+    public void PackedSerialization() {
+      IMessage abstractMessage = new AbstractMessageWrapper(TestUtil.GetPackedSet());
+      TestUtil.AssertPackedFieldsSet(TestPackedTypes.ParseFrom(abstractMessage.ToByteString()));
+      Assert.AreEqual(TestUtil.GetPackedSet().ToByteString(), abstractMessage.ToByteString());
+    }
+
+    [Test]
+    public void PackedParsing() {
+      AbstractMessageWrapper.Builder builder = new AbstractMessageWrapper.Builder(TestPackedTypes.CreateBuilder());
+      AbstractMessageWrapper message = builder.MergeFrom(TestUtil.GetPackedSet().ToByteString()).Build();
+      TestUtil.AssertPackedFieldsSet((TestPackedTypes)message.WrappedMessage);
+    }
+
     [Test]
     public void OptimizedForSize() {
       // We're mostly only Checking that this class was compiled successfully.

+ 12 - 0
src/ProtocolBuffers.Test/CodedOutputStreamTest.cs

@@ -196,6 +196,18 @@ namespace Google.ProtocolBuffers {
       }
     }
 
+    /// <summary>
+    /// Tests writing a whole message with every packed field type. Ensures the
+    /// wire format of packed fields is compatible with C++.
+    /// </summary>
+    [Test]
+    public void WriteWholePackedFieldsMessage() {
+      TestPackedTypes message = TestUtil.GetPackedSet();
+
+      byte[] rawBytes = message.ToByteArray();
+      TestUtil.AssertEqualBytes(TestUtil.GetGoldenPackedFieldsMessage().ToByteArray(),
+                       rawBytes);
+    }
 
     [Test]
     public void EncodeZigZag32() {

+ 29 - 0
src/ProtocolBuffers.Test/DynamicMessageTest.cs

@@ -38,11 +38,13 @@ namespace Google.ProtocolBuffers {
 
     private ReflectionTester reflectionTester;
     private ReflectionTester extensionsReflectionTester;
+    private ReflectionTester packedReflectionTester;
 
     [SetUp]
     public void SetUp() {
       reflectionTester = ReflectionTester.CreateTestAllTypesInstance();
       extensionsReflectionTester = ReflectionTester.CreateTestAllExtensionsInstance();
+      packedReflectionTester = ReflectionTester.CreateTestPackedTypesInstance();
     }
 
     [Test]
@@ -135,6 +137,33 @@ namespace Google.ProtocolBuffers {
       reflectionTester.AssertAllFieldsSetViaReflection(message2);
     }
 
+    [Test]
+      public void DynamicMessagePackedSerialization() {
+    IBuilder builder = DynamicMessage.CreateBuilder(TestPackedTypes.Descriptor);
+    packedReflectionTester.SetPackedFieldsViaReflection(builder);
+    IMessage message = builder.WeakBuild();
+
+    ByteString rawBytes = message.ToByteString();
+    TestPackedTypes message2 = TestPackedTypes.ParseFrom(rawBytes);
+
+    TestUtil.AssertPackedFieldsSet(message2);
+
+    // In fact, the serialized forms should be exactly the same, byte-for-byte.
+    Assert.AreEqual(TestUtil.GetPackedSet().ToByteString(), rawBytes);
+    }
+
+    [Test]
+  public void testDynamicMessagePackedParsing() {
+    TestPackedTypes.Builder builder = TestPackedTypes.CreateBuilder();
+    TestUtil.SetPackedFields(builder);
+    TestPackedTypes message = builder.Build();
+
+    ByteString rawBytes = message.ToByteString();
+
+    IMessage message2 = DynamicMessage.ParseFrom(TestPackedTypes.Descriptor, rawBytes);
+    packedReflectionTester.AssertPackedFieldsSetViaReflection(message2);
+  }
+
     [Test]
     public void DynamicMessageCopy() {
       TestAllTypes.Builder builder = TestAllTypes.CreateBuilder();

文件差異過大導致無法顯示
+ 410 - 400
src/ProtocolBuffers.Test/ReflectionTester.cs


+ 91 - 95
src/ProtocolBuffers.Test/TestProtos/UnitTestCustomOptionsProtoFile.cs

@@ -17,101 +17,97 @@ namespace Google.ProtocolBuffers.TestProtos {
         "Ci1nb29nbGUvcHJvdG9idWYvdW5pdHRlc3RfY3VzdG9tX29wdGlvbnMucHJv" + 
         "dG8SEXByb3RvYnVmX3VuaXR0ZXN0GiRnb29nbGUvcHJvdG9idWYvY3NoYXJw" + 
         "X29wdGlvbnMucHJvdG8aIGdvb2dsZS9wcm90b2J1Zi9kZXNjcmlwdG9yLnBy" + 
-        "b3RvIpoBChxUZXN0TWVzc2FnZVdpdGhDdXN0b21PcHRpb25zEioKBmZpZWxk" + 
-        "MRgBIAEoCUIaCAHB4MMdLeF1CgIAAADB4MMdLeF1CgIAAAAiPAoGQW5FbnVt" + 
-        "Eg8KC0FORU5VTV9WQUwxEAESDwoLQU5FTlVNX1ZBTDIQAhoQxfbJHev8///F" + 
-        "9skd6/z//zoQCADg6cIdyP//////////ASIYChZDdXN0b21PcHRpb25Gb29S" + 
-        "ZXF1ZXN0IhkKF0N1c3RvbU9wdGlvbkZvb1Jlc3BvbnNlIm0KGkR1bW15TWVz" + 
-        "c2FnZUNvbnRhaW5pbmdFbnVtIk8KDFRlc3RFbnVtVHlwZRIaChZURVNUX09Q" + 
-        "VElPTl9FTlVNX1RZUEUxEBYSIwoWVEVTVF9PUFRJT05fRU5VTV9UWVBFMhDp" + 
-        "//////////8BIiEKH0R1bW15TWVzc2FnZUludmFsaWRBc09wdGlvblR5cGUi" + 
-        "swEKHEN1c3RvbU9wdGlvbk1pbkludGVnZXJWYWx1ZXM6kgGZ1qgdAAAAAAAA" + 
-        "AICZ1qgdAAAAAAAAAICtja8dAAAAgK2Nrx0AAACAke6vHQAAAAAAAAAAke6v" + 
-        "HQAAAAAAAAAAnfWvHQAAAACd9a8dAAAAAPiXsB3///////////8BgMSwHf//" + 
-        "//8P+PWwHQCAk7IdALC8sh2AgICAgICAgIAB6MayHYCAgID4/////wHQ3rId" + 
-        "ACK6AQocQ3VzdG9tT3B0aW9uTWF4SW50ZWdlclZhbHVlczqZAZnWqB3/////" + 
-        "////f5nWqB3/////////f62Nrx3///9/rY2vHf///3+R7q8d//////////+R" + 
-        "7q8d//////////+d9a8d/////531rx3/////+JewHf7//////////wGAxLAd" + 
-        "/v///w/49bAd////////////AYCTsh3/////D7C8sh3//////////3/oxrId" + 
-        "/////wfQ3rIdASKCAQoXQ3VzdG9tT3B0aW9uT3RoZXJWYWx1ZXM6Z4jZoh3p" + 
-        "//////////8BstmiHQtIZWxsbwBXb3JsZKrcoh0OSGVsbG8sICJXb3JsZCLp" + 
-        "3KId+1mMQsrA8z/p3KId+1mMQsrA8z/136Md54dFQfXfox3nh0VB6MayHZz/" + 
-        "/////////wEiSAocU2V0dGluZ1JlYWxzRnJvbVBvc2l0aXZlSW50czoo6dyi" + 
-        "HQAAAAAAQGNA6dyiHQAAAAAAQGNA9d+jHQAAQEH136MdAABAQSJIChxTZXR0" + 
-        "aW5nUmVhbHNGcm9tTmVnYXRpdmVJbnRzOijp3KIdAAAAAABAY8Dp3KIdAAAA" + 
-        "AABAY8D136MdAABAwfXfox0AAEDBIisKEkNvbXBsZXhPcHRpb25UeXBlMRIL" + 
-        "CgNmb28YASABKAUqCAhkEICAgIACIsECChJDb21wbGV4T3B0aW9uVHlwZTIS" + 
-        "MgoDYmFyGAEgASgLMiUucHJvdG9idWZfdW5pdHRlc3QuQ29tcGxleE9wdGlv" + 
-        "blR5cGUxEgsKA2JhehgCIAEoBRJGCgRmcmVkGAMgASgLMjgucHJvdG9idWZf" + 
-        "dW5pdHRlc3QuQ29tcGxleE9wdGlvblR5cGUyLkNvbXBsZXhPcHRpb25UeXBl" + 
-        "NBqXAQoSQ29tcGxleE9wdGlvblR5cGU0Eg0KBXdhbGRvGAEgASgFMnIKDGNv" + 
-        "bXBsZXhfb3B0NBIfLmdvb2dsZS5wcm90b2J1Zi5NZXNzYWdlT3B0aW9ucxiK" + 
-        "9dEDIAEoCzI4LnByb3RvYnVmX3VuaXR0ZXN0LkNvbXBsZXhPcHRpb25UeXBl" + 
-        "Mi5Db21wbGV4T3B0aW9uVHlwZTQqCAhkEICAgIACIpwBChJDb21wbGV4T3B0" + 
-        "aW9uVHlwZTMSCwoDcXV4GAEgASgFElQKEmNvbXBsZXhvcHRpb250eXBlNRgC" + 
-        "IAEoCjI4LnByb3RvYnVmX3VuaXR0ZXN0LkNvbXBsZXhPcHRpb25UeXBlMy5D" + 
-        "b21wbGV4T3B0aW9uVHlwZTUaIwoSQ29tcGxleE9wdGlvblR5cGU1Eg0KBXBs" + 
-        "dWdoGAMgASgFIh8KC0NvbXBsZXhPcHQ2EhAKBXh5enp5GN+/zwMgASgFItAB" + 
-        "ChVWYXJpb3VzQ29tcGxleE9wdGlvbnM6tgHj3Pwc+P37HBjk3Pwc0qiPHQMI" + 
-        "sw/63pAdAggJ+t6QHQQTGBYUqv2QHQMQ2weq/ZAdBvjmlx2OBar9kB0FCgMI" + 
-        "5wWq/ZAdCAoG2IWeHc8Pqv2QHQoKCJL1nR0DCNgPqv2QHQjCrJcdAwjlBar9" + 
-        "kB0LwqyXHQbYhZ4dzg+q/ZAdDcKslx0IkvWdHQMIyRCq/ZAdBRoDCMECouKV" + 
-        "HQIIKqLilR0G2IWeHcQCouKVHQiS9Z0dAwjsBio2CgpNZXRob2RPcHQxEhMK" + 
-        "D01FVEhPRE9QVDFfVkFMMRABEhMKD01FVEhPRE9QVDFfVkFMMhACMo4BChxU" + 
-        "ZXN0U2VydmljZVdpdGhDdXN0b21PcHRpb25zEmMKA0ZvbxIpLnByb3RvYnVm" + 
-        "X3VuaXR0ZXN0LkN1c3RvbU9wdGlvbkZvb1JlcXVlc3QaKi5wcm90b2J1Zl91" + 
-        "bml0dGVzdC5DdXN0b21PcHRpb25Gb29SZXNwb25zZSIF4PqMHgIaCZCyix7T" + 
-        "24DLSToyCglmaWxlX29wdDESHC5nb29nbGUucHJvdG9idWYuRmlsZU9wdGlv" + 
-        "bnMYjp3YAyABKAQ6OAoMbWVzc2FnZV9vcHQxEh8uZ29vZ2xlLnByb3RvYnVm" + 
-        "Lk1lc3NhZ2VPcHRpb25zGJyt2AMgASgFOjQKCmZpZWxkX29wdDESHS5nb29n" + 
-        "bGUucHJvdG9idWYuRmllbGRPcHRpb25zGIi82AMgASgGOjgKCmZpZWxkX29w" + 
-        "dDISHS5nb29nbGUucHJvdG9idWYuRmllbGRPcHRpb25zGLmh2QMgASgFOgI0" + 
-        "MjoyCgllbnVtX29wdDESHC5nb29nbGUucHJvdG9idWYuRW51bU9wdGlvbnMY" + 
-        "6J7ZAyABKA86OAoMc2VydmljZV9vcHQxEh8uZ29vZ2xlLnByb3RvYnVmLlNl" + 
-        "cnZpY2VPcHRpb25zGKK24QMgASgSOlUKC21ldGhvZF9vcHQxEh4uZ29vZ2xl" + 
-        "LnByb3RvYnVmLk1ldGhvZE9wdGlvbnMYrM/hAyABKA4yHS5wcm90b2J1Zl91" + 
-        "bml0dGVzdC5NZXRob2RPcHQxOjQKCGJvb2xfb3B0Eh8uZ29vZ2xlLnByb3Rv" + 
-        "YnVmLk1lc3NhZ2VPcHRpb25zGOqr1gMgASgIOjUKCWludDMyX29wdBIfLmdv" + 
-        "b2dsZS5wcm90b2J1Zi5NZXNzYWdlT3B0aW9ucxjtqNYDIAEoBTo1CglpbnQ2" + 
-        "NF9vcHQSHy5nb29nbGUucHJvdG9idWYuTWVzc2FnZU9wdGlvbnMYxqfWAyAB" + 
-        "KAM6NgoKdWludDMyX29wdBIfLmdvb2dsZS5wcm90b2J1Zi5NZXNzYWdlT3B0" + 
-        "aW9ucxiwotYDIAEoDTo2Cgp1aW50NjRfb3B0Eh8uZ29vZ2xlLnByb3RvYnVm" + 
-        "Lk1lc3NhZ2VPcHRpb25zGN+O1gMgASgEOjYKCnNpbnQzMl9vcHQSHy5nb29n" + 
-        "bGUucHJvdG9idWYuTWVzc2FnZU9wdGlvbnMYwIjWAyABKBE6NgoKc2ludDY0" + 
-        "X29wdBIfLmdvb2dsZS5wcm90b2J1Zi5NZXNzYWdlT3B0aW9ucxj/gtYDIAEo" + 
-        "Ejo3CgtmaXhlZDMyX29wdBIfLmdvb2dsZS5wcm90b2J1Zi5NZXNzYWdlT3B0" + 
-        "aW9ucxjT/tUDIAEoBzo3CgtmaXhlZDY0X29wdBIfLmdvb2dsZS5wcm90b2J1" + 
-        "Zi5NZXNzYWdlT3B0aW9ucxji/dUDIAEoBjo4CgxzZml4ZWQzMl9vcHQSHy5n" + 
-        "b29nbGUucHJvdG9idWYuTWVzc2FnZU9wdGlvbnMY1fHVAyABKA86OAoMc2Zp" + 
-        "eGVkNjRfb3B0Eh8uZ29vZ2xlLnByb3RvYnVmLk1lc3NhZ2VPcHRpb25zGOOK" + 
-        "1QMgASgQOjUKCWZsb2F0X29wdBIfLmdvb2dsZS5wcm90b2J1Zi5NZXNzYWdl" + 
-        "T3B0aW9ucxj+u9QDIAEoAjo2Cgpkb3VibGVfb3B0Eh8uZ29vZ2xlLnByb3Rv" + 
-        "YnVmLk1lc3NhZ2VPcHRpb25zGM2r1AMgASgBOjYKCnN0cmluZ19vcHQSHy5n" + 
-        "b29nbGUucHJvdG9idWYuTWVzc2FnZU9wdGlvbnMYxavUAyABKAk6NQoJYnl0" + 
-        "ZXNfb3B0Eh8uZ29vZ2xlLnByb3RvYnVmLk1lc3NhZ2VPcHRpb25zGJar1AMg" + 
-        "ASgMOnAKCGVudW1fb3B0Eh8uZ29vZ2xlLnByb3RvYnVmLk1lc3NhZ2VPcHRp" + 
-        "b25zGJGr1AMgASgOMjoucHJvdG9idWZfdW5pdHRlc3QuRHVtbXlNZXNzYWdl" + 
-        "Q29udGFpbmluZ0VudW0uVGVzdEVudW1UeXBlOnAKEG1lc3NhZ2VfdHlwZV9v" + 
-        "cHQSHy5nb29nbGUucHJvdG9idWYuTWVzc2FnZU9wdGlvbnMYr/LTAyABKAsy" + 
-        "Mi5wcm90b2J1Zl91bml0dGVzdC5EdW1teU1lc3NhZ2VJbnZhbGlkQXNPcHRp" + 
-        "b25UeXBlOjYKBHF1dXgSJS5wcm90b2J1Zl91bml0dGVzdC5Db21wbGV4T3B0" + 
-        "aW9uVHlwZTEY2+DTAyABKAU6XgoFY29yZ2USJS5wcm90b2J1Zl91bml0dGVz" + 
-        "dC5Db21wbGV4T3B0aW9uVHlwZTEY0t7TAyABKAsyJS5wcm90b2J1Zl91bml0" + 
-        "dGVzdC5Db21wbGV4T3B0aW9uVHlwZTM6OAoGZ3JhdWx0EiUucHJvdG9idWZf" + 
-        "dW5pdHRlc3QuQ29tcGxleE9wdGlvblR5cGUyGO/80gMgASgFOl8KBmdhcnBs" + 
-        "eRIlLnByb3RvYnVmX3VuaXR0ZXN0LkNvbXBsZXhPcHRpb25UeXBlMhjI9dID" + 
-        "IAEoCzIlLnByb3RvYnVmX3VuaXR0ZXN0LkNvbXBsZXhPcHRpb25UeXBlMTpf" + 
-        "Cgxjb21wbGV4X29wdDESHy5nb29nbGUucHJvdG9idWYuTWVzc2FnZU9wdGlv" + 
-        "bnMYpNzSAyABKAsyJS5wcm90b2J1Zl91bml0dGVzdC5Db21wbGV4T3B0aW9u" + 
-        "VHlwZTE6XwoMY29tcGxleF9vcHQyEh8uZ29vZ2xlLnByb3RvYnVmLk1lc3Nh" + 
-        "Z2VPcHRpb25zGNWP0gMgASgLMiUucHJvdG9idWZfdW5pdHRlc3QuQ29tcGxl" + 
-        "eE9wdGlvblR5cGUyOl8KDGNvbXBsZXhfb3B0MxIfLmdvb2dsZS5wcm90b2J1" + 
-        "Zi5NZXNzYWdlT3B0aW9ucxjvi9IDIAEoCzIlLnByb3RvYnVmX3VuaXR0ZXN0" + 
-        "LkNvbXBsZXhPcHRpb25UeXBlMzpXCgtjb21wbGV4b3B0NhIfLmdvb2dsZS5w" + 
-        "cm90b2J1Zi5NZXNzYWdlT3B0aW9ucxjMy88DIAEoCjIeLnByb3RvYnVmX3Vu" + 
-        "aXR0ZXN0LkNvbXBsZXhPcHQ2Qk/CPkMKIUdvb2dsZS5Qcm90b2NvbEJ1ZmZl" + 
-        "cnMuVGVzdFByb3RvcxIeVW5pdFRlc3RDdXN0b21PcHRpb25zUHJvdG9GaWxl" + 
-        "8OjBHeqtwOUk"),
+        "b3RvIoYBChxUZXN0TWVzc2FnZVdpdGhDdXN0b21PcHRpb25zEh4KBmZpZWxk" + 
+        "MRgBIAEoCUIOCAHB4MMdLeF1CgIAAAAiNAoGQW5FbnVtEg8KC0FORU5VTV9W" + 
+        "QUwxEAESDwoLQU5FTlVNX1ZBTDIQAhoIxfbJHev8//86EAgA4OnCHcj/////" + 
+        "/////wEiGAoWQ3VzdG9tT3B0aW9uRm9vUmVxdWVzdCIZChdDdXN0b21PcHRp" + 
+        "b25Gb29SZXNwb25zZSJtChpEdW1teU1lc3NhZ2VDb250YWluaW5nRW51bSJP" + 
+        "CgxUZXN0RW51bVR5cGUSGgoWVEVTVF9PUFRJT05fRU5VTV9UWVBFMRAWEiMK" + 
+        "FlRFU1RfT1BUSU9OX0VOVU1fVFlQRTIQ6f//////////ASIhCh9EdW1teU1l" + 
+        "c3NhZ2VJbnZhbGlkQXNPcHRpb25UeXBlIooBChxDdXN0b21PcHRpb25NaW5J" + 
+        "bnRlZ2VyVmFsdWVzOmqZ1qgdAAAAAAAAAICtja8dAAAAgJHurx0AAAAAAAAA" + 
+        "AJ31rx0AAAAA+JewHf///////////wGAxLAd/////w/49bAdAICTsh0AsLyy" + 
+        "HYCAgICAgICAgAHoxrIdgICAgPj/////AdDesh0AIpEBChxDdXN0b21PcHRp" + 
+        "b25NYXhJbnRlZ2VyVmFsdWVzOnGZ1qgd/////////3+tja8d////f5Hurx3/" + 
+        "/////////531rx3/////+JewHf7//////////wGAxLAd/v///w/49bAd////" + 
+        "////////AYCTsh3/////D7C8sh3//////////3/oxrId/////wfQ3rIdASJu" + 
+        "ChdDdXN0b21PcHRpb25PdGhlclZhbHVlczpTiNmiHen//////////wGy2aId" + 
+        "C0hlbGxvAFdvcmxkqtyiHQ5IZWxsbywgIldvcmxkIuncoh37WYxCysDzP/Xf" + 
+        "ox3nh0VB6MayHZz//////////wEiNAocU2V0dGluZ1JlYWxzRnJvbVBvc2l0" + 
+        "aXZlSW50czoU6dyiHQAAAAAAQGNA9d+jHQAAQEEiNAocU2V0dGluZ1JlYWxz" + 
+        "RnJvbU5lZ2F0aXZlSW50czoU6dyiHQAAAAAAQGPA9d+jHQAAQMEiKwoSQ29t" + 
+        "cGxleE9wdGlvblR5cGUxEgsKA2ZvbxgBIAEoBSoICGQQgICAgAIiwQIKEkNv" + 
+        "bXBsZXhPcHRpb25UeXBlMhIyCgNiYXIYASABKAsyJS5wcm90b2J1Zl91bml0" + 
+        "dGVzdC5Db21wbGV4T3B0aW9uVHlwZTESCwoDYmF6GAIgASgFEkYKBGZyZWQY" + 
+        "AyABKAsyOC5wcm90b2J1Zl91bml0dGVzdC5Db21wbGV4T3B0aW9uVHlwZTIu" + 
+        "Q29tcGxleE9wdGlvblR5cGU0GpcBChJDb21wbGV4T3B0aW9uVHlwZTQSDQoF" + 
+        "d2FsZG8YASABKAUycgoMY29tcGxleF9vcHQ0Eh8uZ29vZ2xlLnByb3RvYnVm" + 
+        "Lk1lc3NhZ2VPcHRpb25zGIr10QMgASgLMjgucHJvdG9idWZfdW5pdHRlc3Qu" + 
+        "Q29tcGxleE9wdGlvblR5cGUyLkNvbXBsZXhPcHRpb25UeXBlNCoICGQQgICA" + 
+        "gAIinAEKEkNvbXBsZXhPcHRpb25UeXBlMxILCgNxdXgYASABKAUSVAoSY29t" + 
+        "cGxleG9wdGlvbnR5cGU1GAIgASgKMjgucHJvdG9idWZfdW5pdHRlc3QuQ29t" + 
+        "cGxleE9wdGlvblR5cGUzLkNvbXBsZXhPcHRpb25UeXBlNRojChJDb21wbGV4" + 
+        "T3B0aW9uVHlwZTUSDQoFcGx1Z2gYAyABKAUiHwoLQ29tcGxleE9wdDYSEAoF" + 
+        "eHl6enkY37/PAyABKAUi0AEKFVZhcmlvdXNDb21wbGV4T3B0aW9uczq2AePc" + 
+        "/Bz4/fscGOTc/BzSqI8dAwizD/rekB0CCAn63pAdBBMYFhSq/ZAdAxDbB6r9" + 
+        "kB0G+OaXHY4Fqv2QHQUKAwjnBar9kB0ICgbYhZ4dzw+q/ZAdCgoIkvWdHQMI" + 
+        "2A+q/ZAdCMKslx0DCOUFqv2QHQvCrJcdBtiFnh3OD6r9kB0NwqyXHQiS9Z0d" + 
+        "AwjJEKr9kB0FGgMIwQKi4pUdAggqouKVHQbYhZ4dxAKi4pUdCJL1nR0DCOwG" + 
+        "KjYKCk1ldGhvZE9wdDESEwoPTUVUSE9ET1BUMV9WQUwxEAESEwoPTUVUSE9E" + 
+        "T1BUMV9WQUwyEAIyjgEKHFRlc3RTZXJ2aWNlV2l0aEN1c3RvbU9wdGlvbnMS" + 
+        "YwoDRm9vEikucHJvdG9idWZfdW5pdHRlc3QuQ3VzdG9tT3B0aW9uRm9vUmVx" + 
+        "dWVzdBoqLnByb3RvYnVmX3VuaXR0ZXN0LkN1c3RvbU9wdGlvbkZvb1Jlc3Bv" + 
+        "bnNlIgXg+oweAhoJkLKLHtPbgMtJOjIKCWZpbGVfb3B0MRIcLmdvb2dsZS5w" + 
+        "cm90b2J1Zi5GaWxlT3B0aW9ucxiOndgDIAEoBDo4CgxtZXNzYWdlX29wdDES" + 
+        "Hy5nb29nbGUucHJvdG9idWYuTWVzc2FnZU9wdGlvbnMYnK3YAyABKAU6NAoK" + 
+        "ZmllbGRfb3B0MRIdLmdvb2dsZS5wcm90b2J1Zi5GaWVsZE9wdGlvbnMYiLzY" + 
+        "AyABKAY6OAoKZmllbGRfb3B0MhIdLmdvb2dsZS5wcm90b2J1Zi5GaWVsZE9w" + 
+        "dGlvbnMYuaHZAyABKAU6AjQyOjIKCWVudW1fb3B0MRIcLmdvb2dsZS5wcm90" + 
+        "b2J1Zi5FbnVtT3B0aW9ucxjontkDIAEoDzo4CgxzZXJ2aWNlX29wdDESHy5n" + 
+        "b29nbGUucHJvdG9idWYuU2VydmljZU9wdGlvbnMYorbhAyABKBI6VQoLbWV0" + 
+        "aG9kX29wdDESHi5nb29nbGUucHJvdG9idWYuTWV0aG9kT3B0aW9ucxisz+ED" + 
+        "IAEoDjIdLnByb3RvYnVmX3VuaXR0ZXN0Lk1ldGhvZE9wdDE6NAoIYm9vbF9v" + 
+        "cHQSHy5nb29nbGUucHJvdG9idWYuTWVzc2FnZU9wdGlvbnMY6qvWAyABKAg6" + 
+        "NQoJaW50MzJfb3B0Eh8uZ29vZ2xlLnByb3RvYnVmLk1lc3NhZ2VPcHRpb25z" + 
+        "GO2o1gMgASgFOjUKCWludDY0X29wdBIfLmdvb2dsZS5wcm90b2J1Zi5NZXNz" + 
+        "YWdlT3B0aW9ucxjGp9YDIAEoAzo2Cgp1aW50MzJfb3B0Eh8uZ29vZ2xlLnBy" + 
+        "b3RvYnVmLk1lc3NhZ2VPcHRpb25zGLCi1gMgASgNOjYKCnVpbnQ2NF9vcHQS" + 
+        "Hy5nb29nbGUucHJvdG9idWYuTWVzc2FnZU9wdGlvbnMY347WAyABKAQ6NgoK" + 
+        "c2ludDMyX29wdBIfLmdvb2dsZS5wcm90b2J1Zi5NZXNzYWdlT3B0aW9ucxjA" + 
+        "iNYDIAEoETo2CgpzaW50NjRfb3B0Eh8uZ29vZ2xlLnByb3RvYnVmLk1lc3Nh" + 
+        "Z2VPcHRpb25zGP+C1gMgASgSOjcKC2ZpeGVkMzJfb3B0Eh8uZ29vZ2xlLnBy" + 
+        "b3RvYnVmLk1lc3NhZ2VPcHRpb25zGNP+1QMgASgHOjcKC2ZpeGVkNjRfb3B0" + 
+        "Eh8uZ29vZ2xlLnByb3RvYnVmLk1lc3NhZ2VPcHRpb25zGOL91QMgASgGOjgK" + 
+        "DHNmaXhlZDMyX29wdBIfLmdvb2dsZS5wcm90b2J1Zi5NZXNzYWdlT3B0aW9u" + 
+        "cxjV8dUDIAEoDzo4CgxzZml4ZWQ2NF9vcHQSHy5nb29nbGUucHJvdG9idWYu" + 
+        "TWVzc2FnZU9wdGlvbnMY44rVAyABKBA6NQoJZmxvYXRfb3B0Eh8uZ29vZ2xl" + 
+        "LnByb3RvYnVmLk1lc3NhZ2VPcHRpb25zGP671AMgASgCOjYKCmRvdWJsZV9v" + 
+        "cHQSHy5nb29nbGUucHJvdG9idWYuTWVzc2FnZU9wdGlvbnMYzavUAyABKAE6" + 
+        "NgoKc3RyaW5nX29wdBIfLmdvb2dsZS5wcm90b2J1Zi5NZXNzYWdlT3B0aW9u" + 
+        "cxjFq9QDIAEoCTo1CglieXRlc19vcHQSHy5nb29nbGUucHJvdG9idWYuTWVz" + 
+        "c2FnZU9wdGlvbnMYlqvUAyABKAw6cAoIZW51bV9vcHQSHy5nb29nbGUucHJv" + 
+        "dG9idWYuTWVzc2FnZU9wdGlvbnMYkavUAyABKA4yOi5wcm90b2J1Zl91bml0" + 
+        "dGVzdC5EdW1teU1lc3NhZ2VDb250YWluaW5nRW51bS5UZXN0RW51bVR5cGU6" + 
+        "cAoQbWVzc2FnZV90eXBlX29wdBIfLmdvb2dsZS5wcm90b2J1Zi5NZXNzYWdl" + 
+        "T3B0aW9ucxiv8tMDIAEoCzIyLnByb3RvYnVmX3VuaXR0ZXN0LkR1bW15TWVz" + 
+        "c2FnZUludmFsaWRBc09wdGlvblR5cGU6NgoEcXV1eBIlLnByb3RvYnVmX3Vu" + 
+        "aXR0ZXN0LkNvbXBsZXhPcHRpb25UeXBlMRjb4NMDIAEoBTpeCgVjb3JnZRIl" + 
+        "LnByb3RvYnVmX3VuaXR0ZXN0LkNvbXBsZXhPcHRpb25UeXBlMRjS3tMDIAEo" + 
+        "CzIlLnByb3RvYnVmX3VuaXR0ZXN0LkNvbXBsZXhPcHRpb25UeXBlMzo4CgZn" + 
+        "cmF1bHQSJS5wcm90b2J1Zl91bml0dGVzdC5Db21wbGV4T3B0aW9uVHlwZTIY" + 
+        "7/zSAyABKAU6XwoGZ2FycGx5EiUucHJvdG9idWZfdW5pdHRlc3QuQ29tcGxl" + 
+        "eE9wdGlvblR5cGUyGMj10gMgASgLMiUucHJvdG9idWZfdW5pdHRlc3QuQ29t" + 
+        "cGxleE9wdGlvblR5cGUxOl8KDGNvbXBsZXhfb3B0MRIfLmdvb2dsZS5wcm90" + 
+        "b2J1Zi5NZXNzYWdlT3B0aW9ucxik3NIDIAEoCzIlLnByb3RvYnVmX3VuaXR0" + 
+        "ZXN0LkNvbXBsZXhPcHRpb25UeXBlMTpfCgxjb21wbGV4X29wdDISHy5nb29n" + 
+        "bGUucHJvdG9idWYuTWVzc2FnZU9wdGlvbnMY1Y/SAyABKAsyJS5wcm90b2J1" + 
+        "Zl91bml0dGVzdC5Db21wbGV4T3B0aW9uVHlwZTI6XwoMY29tcGxleF9vcHQz" + 
+        "Eh8uZ29vZ2xlLnByb3RvYnVmLk1lc3NhZ2VPcHRpb25zGO+L0gMgASgLMiUu" + 
+        "cHJvdG9idWZfdW5pdHRlc3QuQ29tcGxleE9wdGlvblR5cGUzOlcKC2NvbXBs" + 
+        "ZXhvcHQ2Eh8uZ29vZ2xlLnByb3RvYnVmLk1lc3NhZ2VPcHRpb25zGMzLzwMg" + 
+        "ASgKMh4ucHJvdG9idWZfdW5pdHRlc3QuQ29tcGxleE9wdDZCT8I+QwohR29v" + 
+        "Z2xlLlByb3RvY29sQnVmZmVycy5UZXN0UHJvdG9zEh5Vbml0VGVzdEN1c3Rv" + 
+        "bU9wdGlvbnNQcm90b0ZpbGXw6MEd6q3A5SQ="),
         new pbd::FileDescriptor[] {
           global::Google.ProtocolBuffers.DescriptorProtos.CSharpOptions.Descriptor, 
           global::Google.ProtocolBuffers.DescriptorProtos.DescriptorProtoFile.Descriptor, 

+ 1784 - 266
src/ProtocolBuffers.Test/TestProtos/UnitTestProtoFile.cs

@@ -139,153 +139,189 @@ namespace Google.ProtocolBuffers.TestProtos {
         "Z2VfdWludDMyGAIgASgNOgo0Mjk0OTY3Mjk1EioKDGxhcmdlX3VpbnQ2NBgD" + 
         "IAEoBDoUMTg0NDY3NDQwNzM3MDk1NTE2MTUSIAoLc21hbGxfaW50MzIYBCAB" + 
         "KAU6Cy0yMTQ3NDgzNjQ3EikKC3NtYWxsX2ludDY0GAUgASgDOhQtOTIyMzM3" + 
-        "MjAzNjg1NDc3NTgwNxIYCgt1dGY4X3N0cmluZxgGIAEoCToD4Yi0IgwKCkZv" + 
-        "b1JlcXVlc3QiDQoLRm9vUmVzcG9uc2UiDAoKQmFyUmVxdWVzdCINCgtCYXJS" + 
-        "ZXNwb25zZSpACgtGb3JlaWduRW51bRIPCgtGT1JFSUdOX0ZPTxAEEg8KC0ZP" + 
-        "UkVJR05fQkFSEAUSDwoLRk9SRUlHTl9CQVoQBipHChRUZXN0RW51bVdpdGhE" + 
-        "dXBWYWx1ZRIICgRGT08xEAESCAoEQkFSMRACEgcKA0JBWhADEggKBEZPTzIQ" + 
-        "ARIICgRCQVIyEAIqiQEKDlRlc3RTcGFyc2VFbnVtEgwKCFNQQVJTRV9BEHsS" + 
-        "DgoIU1BBUlNFX0IQpucDEg8KCFNQQVJTRV9DELKxgAYSFQoIU1BBUlNFX0QQ" + 
-        "8f//////////ARIVCghTUEFSU0VfRRC03vz///////8BEgwKCFNQQVJTRV9G" + 
-        "EAASDAoIU1BBUlNFX0cQAjKZAQoLVGVzdFNlcnZpY2USRAoDRm9vEh0ucHJv" + 
-        "dG9idWZfdW5pdHRlc3QuRm9vUmVxdWVzdBoeLnByb3RvYnVmX3VuaXR0ZXN0" + 
-        "LkZvb1Jlc3BvbnNlEkQKA0JhchIdLnByb3RvYnVmX3VuaXR0ZXN0LkJhclJl" + 
-        "cXVlc3QaHi5wcm90b2J1Zl91bml0dGVzdC5CYXJSZXNwb25zZTpGChhvcHRp" + 
-        "b25hbF9pbnQzMl9leHRlbnNpb24SJC5wcm90b2J1Zl91bml0dGVzdC5UZXN0" + 
-        "QWxsRXh0ZW5zaW9ucxgBIAEoBTpGChhvcHRpb25hbF9pbnQ2NF9leHRlbnNp" + 
-        "b24SJC5wcm90b2J1Zl91bml0dGVzdC5UZXN0QWxsRXh0ZW5zaW9ucxgCIAEo" + 
-        "AzpHChlvcHRpb25hbF91aW50MzJfZXh0ZW5zaW9uEiQucHJvdG9idWZfdW5p" + 
-        "dHRlc3QuVGVzdEFsbEV4dGVuc2lvbnMYAyABKA06RwoZb3B0aW9uYWxfdWlu" + 
-        "dDY0X2V4dGVuc2lvbhIkLnByb3RvYnVmX3VuaXR0ZXN0LlRlc3RBbGxFeHRl" + 
-        "bnNpb25zGAQgASgEOkcKGW9wdGlvbmFsX3NpbnQzMl9leHRlbnNpb24SJC5w" + 
-        "cm90b2J1Zl91bml0dGVzdC5UZXN0QWxsRXh0ZW5zaW9ucxgFIAEoETpHChlv" + 
-        "cHRpb25hbF9zaW50NjRfZXh0ZW5zaW9uEiQucHJvdG9idWZfdW5pdHRlc3Qu" + 
-        "VGVzdEFsbEV4dGVuc2lvbnMYBiABKBI6SAoab3B0aW9uYWxfZml4ZWQzMl9l" + 
-        "eHRlbnNpb24SJC5wcm90b2J1Zl91bml0dGVzdC5UZXN0QWxsRXh0ZW5zaW9u" + 
-        "cxgHIAEoBzpIChpvcHRpb25hbF9maXhlZDY0X2V4dGVuc2lvbhIkLnByb3Rv" + 
-        "YnVmX3VuaXR0ZXN0LlRlc3RBbGxFeHRlbnNpb25zGAggASgGOkkKG29wdGlv" + 
-        "bmFsX3NmaXhlZDMyX2V4dGVuc2lvbhIkLnByb3RvYnVmX3VuaXR0ZXN0LlRl" + 
-        "c3RBbGxFeHRlbnNpb25zGAkgASgPOkkKG29wdGlvbmFsX3NmaXhlZDY0X2V4" + 
-        "dGVuc2lvbhIkLnByb3RvYnVmX3VuaXR0ZXN0LlRlc3RBbGxFeHRlbnNpb25z" + 
-        "GAogASgQOkYKGG9wdGlvbmFsX2Zsb2F0X2V4dGVuc2lvbhIkLnByb3RvYnVm" + 
-        "X3VuaXR0ZXN0LlRlc3RBbGxFeHRlbnNpb25zGAsgASgCOkcKGW9wdGlvbmFs" + 
-        "X2RvdWJsZV9leHRlbnNpb24SJC5wcm90b2J1Zl91bml0dGVzdC5UZXN0QWxs" + 
-        "RXh0ZW5zaW9ucxgMIAEoATpFChdvcHRpb25hbF9ib29sX2V4dGVuc2lvbhIk" + 
-        "LnByb3RvYnVmX3VuaXR0ZXN0LlRlc3RBbGxFeHRlbnNpb25zGA0gASgIOkcK" + 
-        "GW9wdGlvbmFsX3N0cmluZ19leHRlbnNpb24SJC5wcm90b2J1Zl91bml0dGVz" + 
-        "dC5UZXN0QWxsRXh0ZW5zaW9ucxgOIAEoCTpGChhvcHRpb25hbF9ieXRlc19l" + 
+        "MjAzNjg1NDc3NTgwNxIYCgt1dGY4X3N0cmluZxgGIAEoCToD4Yi0IqoDCg9U" + 
+        "ZXN0UGFja2VkVHlwZXMSGAoMcGFja2VkX2ludDMyGFogAygFQgIQARIYCgxw" + 
+        "YWNrZWRfaW50NjQYWyADKANCAhABEhkKDXBhY2tlZF91aW50MzIYXCADKA1C" + 
+        "AhABEhkKDXBhY2tlZF91aW50NjQYXSADKARCAhABEhkKDXBhY2tlZF9zaW50" + 
+        "MzIYXiADKBFCAhABEhkKDXBhY2tlZF9zaW50NjQYXyADKBJCAhABEhoKDnBh" + 
+        "Y2tlZF9maXhlZDMyGGAgAygHQgIQARIaCg5wYWNrZWRfZml4ZWQ2NBhhIAMo" + 
+        "BkICEAESGwoPcGFja2VkX3NmaXhlZDMyGGIgAygPQgIQARIbCg9wYWNrZWRf" + 
+        "c2ZpeGVkNjQYYyADKBBCAhABEhgKDHBhY2tlZF9mbG9hdBhkIAMoAkICEAES" + 
+        "GQoNcGFja2VkX2RvdWJsZRhlIAMoAUICEAESFwoLcGFja2VkX2Jvb2wYZiAD" + 
+        "KAhCAhABEjcKC3BhY2tlZF9lbnVtGGcgAygOMh4ucHJvdG9idWZfdW5pdHRl" + 
+        "c3QuRm9yZWlnbkVudW1CAhABIiAKFFRlc3RQYWNrZWRFeHRlbnNpb25zKggI" + 
+        "ARCAgICAAiIMCgpGb29SZXF1ZXN0Ig0KC0Zvb1Jlc3BvbnNlIgwKCkJhclJl" + 
+        "cXVlc3QiDQoLQmFyUmVzcG9uc2UqQAoLRm9yZWlnbkVudW0SDwoLRk9SRUlH" + 
+        "Tl9GT08QBBIPCgtGT1JFSUdOX0JBUhAFEg8KC0ZPUkVJR05fQkFaEAYqRwoU" + 
+        "VGVzdEVudW1XaXRoRHVwVmFsdWUSCAoERk9PMRABEggKBEJBUjEQAhIHCgNC" + 
+        "QVoQAxIICgRGT08yEAESCAoEQkFSMhACKokBCg5UZXN0U3BhcnNlRW51bRIM" + 
+        "CghTUEFSU0VfQRB7Eg4KCFNQQVJTRV9CEKbnAxIPCghTUEFSU0VfQxCysYAG" + 
+        "EhUKCFNQQVJTRV9EEPH//////////wESFQoIU1BBUlNFX0UQtN78////////" + 
+        "ARIMCghTUEFSU0VfRhAAEgwKCFNQQVJTRV9HEAIymQEKC1Rlc3RTZXJ2aWNl" + 
+        "EkQKA0ZvbxIdLnByb3RvYnVmX3VuaXR0ZXN0LkZvb1JlcXVlc3QaHi5wcm90" + 
+        "b2J1Zl91bml0dGVzdC5Gb29SZXNwb25zZRJECgNCYXISHS5wcm90b2J1Zl91" + 
+        "bml0dGVzdC5CYXJSZXF1ZXN0Gh4ucHJvdG9idWZfdW5pdHRlc3QuQmFyUmVz" + 
+        "cG9uc2U6RgoYb3B0aW9uYWxfaW50MzJfZXh0ZW5zaW9uEiQucHJvdG9idWZf" + 
+        "dW5pdHRlc3QuVGVzdEFsbEV4dGVuc2lvbnMYASABKAU6RgoYb3B0aW9uYWxf" + 
+        "aW50NjRfZXh0ZW5zaW9uEiQucHJvdG9idWZfdW5pdHRlc3QuVGVzdEFsbEV4" + 
+        "dGVuc2lvbnMYAiABKAM6RwoZb3B0aW9uYWxfdWludDMyX2V4dGVuc2lvbhIk" + 
+        "LnByb3RvYnVmX3VuaXR0ZXN0LlRlc3RBbGxFeHRlbnNpb25zGAMgASgNOkcK" + 
+        "GW9wdGlvbmFsX3VpbnQ2NF9leHRlbnNpb24SJC5wcm90b2J1Zl91bml0dGVz" + 
+        "dC5UZXN0QWxsRXh0ZW5zaW9ucxgEIAEoBDpHChlvcHRpb25hbF9zaW50MzJf" + 
+        "ZXh0ZW5zaW9uEiQucHJvdG9idWZfdW5pdHRlc3QuVGVzdEFsbEV4dGVuc2lv" + 
+        "bnMYBSABKBE6RwoZb3B0aW9uYWxfc2ludDY0X2V4dGVuc2lvbhIkLnByb3Rv" + 
+        "YnVmX3VuaXR0ZXN0LlRlc3RBbGxFeHRlbnNpb25zGAYgASgSOkgKGm9wdGlv" + 
+        "bmFsX2ZpeGVkMzJfZXh0ZW5zaW9uEiQucHJvdG9idWZfdW5pdHRlc3QuVGVz" + 
+        "dEFsbEV4dGVuc2lvbnMYByABKAc6SAoab3B0aW9uYWxfZml4ZWQ2NF9leHRl" + 
+        "bnNpb24SJC5wcm90b2J1Zl91bml0dGVzdC5UZXN0QWxsRXh0ZW5zaW9ucxgI" + 
+        "IAEoBjpJChtvcHRpb25hbF9zZml4ZWQzMl9leHRlbnNpb24SJC5wcm90b2J1" + 
+        "Zl91bml0dGVzdC5UZXN0QWxsRXh0ZW5zaW9ucxgJIAEoDzpJChtvcHRpb25h" + 
+        "bF9zZml4ZWQ2NF9leHRlbnNpb24SJC5wcm90b2J1Zl91bml0dGVzdC5UZXN0" + 
+        "QWxsRXh0ZW5zaW9ucxgKIAEoEDpGChhvcHRpb25hbF9mbG9hdF9leHRlbnNp" + 
+        "b24SJC5wcm90b2J1Zl91bml0dGVzdC5UZXN0QWxsRXh0ZW5zaW9ucxgLIAEo" + 
+        "AjpHChlvcHRpb25hbF9kb3VibGVfZXh0ZW5zaW9uEiQucHJvdG9idWZfdW5p" + 
+        "dHRlc3QuVGVzdEFsbEV4dGVuc2lvbnMYDCABKAE6RQoXb3B0aW9uYWxfYm9v" + 
+        "bF9leHRlbnNpb24SJC5wcm90b2J1Zl91bml0dGVzdC5UZXN0QWxsRXh0ZW5z" + 
+        "aW9ucxgNIAEoCDpHChlvcHRpb25hbF9zdHJpbmdfZXh0ZW5zaW9uEiQucHJv" + 
+        "dG9idWZfdW5pdHRlc3QuVGVzdEFsbEV4dGVuc2lvbnMYDiABKAk6RgoYb3B0" + 
+        "aW9uYWxfYnl0ZXNfZXh0ZW5zaW9uEiQucHJvdG9idWZfdW5pdHRlc3QuVGVz" + 
+        "dEFsbEV4dGVuc2lvbnMYDyABKAw6cQoXb3B0aW9uYWxncm91cF9leHRlbnNp" + 
+        "b24SJC5wcm90b2J1Zl91bml0dGVzdC5UZXN0QWxsRXh0ZW5zaW9ucxgQIAEo" + 
+        "CjIqLnByb3RvYnVmX3VuaXR0ZXN0Lk9wdGlvbmFsR3JvdXBfZXh0ZW5zaW9u" + 
+        "On4KIW9wdGlvbmFsX25lc3RlZF9tZXNzYWdlX2V4dGVuc2lvbhIkLnByb3Rv" + 
+        "YnVmX3VuaXR0ZXN0LlRlc3RBbGxFeHRlbnNpb25zGBIgASgLMi0ucHJvdG9i" + 
+        "dWZfdW5pdHRlc3QuVGVzdEFsbFR5cGVzLk5lc3RlZE1lc3NhZ2U6cwoib3B0" + 
+        "aW9uYWxfZm9yZWlnbl9tZXNzYWdlX2V4dGVuc2lvbhIkLnByb3RvYnVmX3Vu" + 
+        "aXR0ZXN0LlRlc3RBbGxFeHRlbnNpb25zGBMgASgLMiEucHJvdG9idWZfdW5p" + 
+        "dHRlc3QuRm9yZWlnbk1lc3NhZ2U6eAohb3B0aW9uYWxfaW1wb3J0X21lc3Nh" + 
+        "Z2VfZXh0ZW5zaW9uEiQucHJvdG9idWZfdW5pdHRlc3QuVGVzdEFsbEV4dGVu" + 
+        "c2lvbnMYFCABKAsyJy5wcm90b2J1Zl91bml0dGVzdF9pbXBvcnQuSW1wb3J0" + 
+        "TWVzc2FnZTp4Ch5vcHRpb25hbF9uZXN0ZWRfZW51bV9leHRlbnNpb24SJC5w" + 
+        "cm90b2J1Zl91bml0dGVzdC5UZXN0QWxsRXh0ZW5zaW9ucxgVIAEoDjIqLnBy" + 
+        "b3RvYnVmX3VuaXR0ZXN0LlRlc3RBbGxUeXBlcy5OZXN0ZWRFbnVtOm0KH29w" + 
+        "dGlvbmFsX2ZvcmVpZ25fZW51bV9leHRlbnNpb24SJC5wcm90b2J1Zl91bml0" + 
+        "dGVzdC5UZXN0QWxsRXh0ZW5zaW9ucxgWIAEoDjIeLnByb3RvYnVmX3VuaXR0" + 
+        "ZXN0LkZvcmVpZ25FbnVtOnIKHm9wdGlvbmFsX2ltcG9ydF9lbnVtX2V4dGVu" + 
+        "c2lvbhIkLnByb3RvYnVmX3VuaXR0ZXN0LlRlc3RBbGxFeHRlbnNpb25zGBcg" + 
+        "ASgOMiQucHJvdG9idWZfdW5pdHRlc3RfaW1wb3J0LkltcG9ydEVudW06UQof" + 
+        "b3B0aW9uYWxfc3RyaW5nX3BpZWNlX2V4dGVuc2lvbhIkLnByb3RvYnVmX3Vu" + 
+        "aXR0ZXN0LlRlc3RBbGxFeHRlbnNpb25zGBggASgJQgIIAjpJChdvcHRpb25h" + 
+        "bF9jb3JkX2V4dGVuc2lvbhIkLnByb3RvYnVmX3VuaXR0ZXN0LlRlc3RBbGxF" + 
+        "eHRlbnNpb25zGBkgASgJQgIIATpGChhyZXBlYXRlZF9pbnQzMl9leHRlbnNp" + 
+        "b24SJC5wcm90b2J1Zl91bml0dGVzdC5UZXN0QWxsRXh0ZW5zaW9ucxgfIAMo" + 
+        "BTpGChhyZXBlYXRlZF9pbnQ2NF9leHRlbnNpb24SJC5wcm90b2J1Zl91bml0" + 
+        "dGVzdC5UZXN0QWxsRXh0ZW5zaW9ucxggIAMoAzpHChlyZXBlYXRlZF91aW50" + 
+        "MzJfZXh0ZW5zaW9uEiQucHJvdG9idWZfdW5pdHRlc3QuVGVzdEFsbEV4dGVu" + 
+        "c2lvbnMYISADKA06RwoZcmVwZWF0ZWRfdWludDY0X2V4dGVuc2lvbhIkLnBy" + 
+        "b3RvYnVmX3VuaXR0ZXN0LlRlc3RBbGxFeHRlbnNpb25zGCIgAygEOkcKGXJl" + 
+        "cGVhdGVkX3NpbnQzMl9leHRlbnNpb24SJC5wcm90b2J1Zl91bml0dGVzdC5U" + 
+        "ZXN0QWxsRXh0ZW5zaW9ucxgjIAMoETpHChlyZXBlYXRlZF9zaW50NjRfZXh0" + 
+        "ZW5zaW9uEiQucHJvdG9idWZfdW5pdHRlc3QuVGVzdEFsbEV4dGVuc2lvbnMY" + 
+        "JCADKBI6SAoacmVwZWF0ZWRfZml4ZWQzMl9leHRlbnNpb24SJC5wcm90b2J1" + 
+        "Zl91bml0dGVzdC5UZXN0QWxsRXh0ZW5zaW9ucxglIAMoBzpIChpyZXBlYXRl" + 
+        "ZF9maXhlZDY0X2V4dGVuc2lvbhIkLnByb3RvYnVmX3VuaXR0ZXN0LlRlc3RB" + 
+        "bGxFeHRlbnNpb25zGCYgAygGOkkKG3JlcGVhdGVkX3NmaXhlZDMyX2V4dGVu" + 
+        "c2lvbhIkLnByb3RvYnVmX3VuaXR0ZXN0LlRlc3RBbGxFeHRlbnNpb25zGCcg" + 
+        "AygPOkkKG3JlcGVhdGVkX3NmaXhlZDY0X2V4dGVuc2lvbhIkLnByb3RvYnVm" + 
+        "X3VuaXR0ZXN0LlRlc3RBbGxFeHRlbnNpb25zGCggAygQOkYKGHJlcGVhdGVk" + 
+        "X2Zsb2F0X2V4dGVuc2lvbhIkLnByb3RvYnVmX3VuaXR0ZXN0LlRlc3RBbGxF" + 
+        "eHRlbnNpb25zGCkgAygCOkcKGXJlcGVhdGVkX2RvdWJsZV9leHRlbnNpb24S" + 
+        "JC5wcm90b2J1Zl91bml0dGVzdC5UZXN0QWxsRXh0ZW5zaW9ucxgqIAMoATpF" + 
+        "ChdyZXBlYXRlZF9ib29sX2V4dGVuc2lvbhIkLnByb3RvYnVmX3VuaXR0ZXN0" + 
+        "LlRlc3RBbGxFeHRlbnNpb25zGCsgAygIOkcKGXJlcGVhdGVkX3N0cmluZ19l" + 
         "eHRlbnNpb24SJC5wcm90b2J1Zl91bml0dGVzdC5UZXN0QWxsRXh0ZW5zaW9u" + 
-        "cxgPIAEoDDpxChdvcHRpb25hbGdyb3VwX2V4dGVuc2lvbhIkLnByb3RvYnVm" + 
-        "X3VuaXR0ZXN0LlRlc3RBbGxFeHRlbnNpb25zGBAgASgKMioucHJvdG9idWZf" + 
-        "dW5pdHRlc3QuT3B0aW9uYWxHcm91cF9leHRlbnNpb246fgohb3B0aW9uYWxf" + 
-        "bmVzdGVkX21lc3NhZ2VfZXh0ZW5zaW9uEiQucHJvdG9idWZfdW5pdHRlc3Qu" + 
-        "VGVzdEFsbEV4dGVuc2lvbnMYEiABKAsyLS5wcm90b2J1Zl91bml0dGVzdC5U" + 
-        "ZXN0QWxsVHlwZXMuTmVzdGVkTWVzc2FnZTpzCiJvcHRpb25hbF9mb3JlaWdu" + 
-        "X21lc3NhZ2VfZXh0ZW5zaW9uEiQucHJvdG9idWZfdW5pdHRlc3QuVGVzdEFs" + 
-        "bEV4dGVuc2lvbnMYEyABKAsyIS5wcm90b2J1Zl91bml0dGVzdC5Gb3JlaWdu" + 
-        "TWVzc2FnZTp4CiFvcHRpb25hbF9pbXBvcnRfbWVzc2FnZV9leHRlbnNpb24S" + 
-        "JC5wcm90b2J1Zl91bml0dGVzdC5UZXN0QWxsRXh0ZW5zaW9ucxgUIAEoCzIn" + 
-        "LnByb3RvYnVmX3VuaXR0ZXN0X2ltcG9ydC5JbXBvcnRNZXNzYWdlOngKHm9w" + 
-        "dGlvbmFsX25lc3RlZF9lbnVtX2V4dGVuc2lvbhIkLnByb3RvYnVmX3VuaXR0" + 
-        "ZXN0LlRlc3RBbGxFeHRlbnNpb25zGBUgASgOMioucHJvdG9idWZfdW5pdHRl" + 
-        "c3QuVGVzdEFsbFR5cGVzLk5lc3RlZEVudW06bQofb3B0aW9uYWxfZm9yZWln" + 
-        "bl9lbnVtX2V4dGVuc2lvbhIkLnByb3RvYnVmX3VuaXR0ZXN0LlRlc3RBbGxF" + 
-        "eHRlbnNpb25zGBYgASgOMh4ucHJvdG9idWZfdW5pdHRlc3QuRm9yZWlnbkVu" + 
-        "dW06cgoeb3B0aW9uYWxfaW1wb3J0X2VudW1fZXh0ZW5zaW9uEiQucHJvdG9i" + 
-        "dWZfdW5pdHRlc3QuVGVzdEFsbEV4dGVuc2lvbnMYFyABKA4yJC5wcm90b2J1" + 
-        "Zl91bml0dGVzdF9pbXBvcnQuSW1wb3J0RW51bTpRCh9vcHRpb25hbF9zdHJp" + 
-        "bmdfcGllY2VfZXh0ZW5zaW9uEiQucHJvdG9idWZfdW5pdHRlc3QuVGVzdEFs" + 
-        "bEV4dGVuc2lvbnMYGCABKAlCAggCOkkKF29wdGlvbmFsX2NvcmRfZXh0ZW5z" + 
-        "aW9uEiQucHJvdG9idWZfdW5pdHRlc3QuVGVzdEFsbEV4dGVuc2lvbnMYGSAB" + 
-        "KAlCAggBOkYKGHJlcGVhdGVkX2ludDMyX2V4dGVuc2lvbhIkLnByb3RvYnVm" + 
-        "X3VuaXR0ZXN0LlRlc3RBbGxFeHRlbnNpb25zGB8gAygFOkYKGHJlcGVhdGVk" + 
-        "X2ludDY0X2V4dGVuc2lvbhIkLnByb3RvYnVmX3VuaXR0ZXN0LlRlc3RBbGxF" + 
-        "eHRlbnNpb25zGCAgAygDOkcKGXJlcGVhdGVkX3VpbnQzMl9leHRlbnNpb24S" + 
-        "JC5wcm90b2J1Zl91bml0dGVzdC5UZXN0QWxsRXh0ZW5zaW9ucxghIAMoDTpH" + 
-        "ChlyZXBlYXRlZF91aW50NjRfZXh0ZW5zaW9uEiQucHJvdG9idWZfdW5pdHRl" + 
-        "c3QuVGVzdEFsbEV4dGVuc2lvbnMYIiADKAQ6RwoZcmVwZWF0ZWRfc2ludDMy" + 
-        "X2V4dGVuc2lvbhIkLnByb3RvYnVmX3VuaXR0ZXN0LlRlc3RBbGxFeHRlbnNp" + 
-        "b25zGCMgAygROkcKGXJlcGVhdGVkX3NpbnQ2NF9leHRlbnNpb24SJC5wcm90" + 
-        "b2J1Zl91bml0dGVzdC5UZXN0QWxsRXh0ZW5zaW9ucxgkIAMoEjpIChpyZXBl" + 
-        "YXRlZF9maXhlZDMyX2V4dGVuc2lvbhIkLnByb3RvYnVmX3VuaXR0ZXN0LlRl" + 
-        "c3RBbGxFeHRlbnNpb25zGCUgAygHOkgKGnJlcGVhdGVkX2ZpeGVkNjRfZXh0" + 
+        "cxgsIAMoCTpGChhyZXBlYXRlZF9ieXRlc19leHRlbnNpb24SJC5wcm90b2J1" + 
+        "Zl91bml0dGVzdC5UZXN0QWxsRXh0ZW5zaW9ucxgtIAMoDDpxChdyZXBlYXRl" + 
+        "ZGdyb3VwX2V4dGVuc2lvbhIkLnByb3RvYnVmX3VuaXR0ZXN0LlRlc3RBbGxF" + 
+        "eHRlbnNpb25zGC4gAygKMioucHJvdG9idWZfdW5pdHRlc3QuUmVwZWF0ZWRH" + 
+        "cm91cF9leHRlbnNpb246fgohcmVwZWF0ZWRfbmVzdGVkX21lc3NhZ2VfZXh0" + 
         "ZW5zaW9uEiQucHJvdG9idWZfdW5pdHRlc3QuVGVzdEFsbEV4dGVuc2lvbnMY" + 
-        "JiADKAY6SQobcmVwZWF0ZWRfc2ZpeGVkMzJfZXh0ZW5zaW9uEiQucHJvdG9i" + 
-        "dWZfdW5pdHRlc3QuVGVzdEFsbEV4dGVuc2lvbnMYJyADKA86SQobcmVwZWF0" + 
-        "ZWRfc2ZpeGVkNjRfZXh0ZW5zaW9uEiQucHJvdG9idWZfdW5pdHRlc3QuVGVz" + 
-        "dEFsbEV4dGVuc2lvbnMYKCADKBA6RgoYcmVwZWF0ZWRfZmxvYXRfZXh0ZW5z" + 
-        "aW9uEiQucHJvdG9idWZfdW5pdHRlc3QuVGVzdEFsbEV4dGVuc2lvbnMYKSAD" + 
-        "KAI6RwoZcmVwZWF0ZWRfZG91YmxlX2V4dGVuc2lvbhIkLnByb3RvYnVmX3Vu" + 
-        "aXR0ZXN0LlRlc3RBbGxFeHRlbnNpb25zGCogAygBOkUKF3JlcGVhdGVkX2Jv" + 
-        "b2xfZXh0ZW5zaW9uEiQucHJvdG9idWZfdW5pdHRlc3QuVGVzdEFsbEV4dGVu" + 
-        "c2lvbnMYKyADKAg6RwoZcmVwZWF0ZWRfc3RyaW5nX2V4dGVuc2lvbhIkLnBy" + 
-        "b3RvYnVmX3VuaXR0ZXN0LlRlc3RBbGxFeHRlbnNpb25zGCwgAygJOkYKGHJl" + 
-        "cGVhdGVkX2J5dGVzX2V4dGVuc2lvbhIkLnByb3RvYnVmX3VuaXR0ZXN0LlRl" + 
-        "c3RBbGxFeHRlbnNpb25zGC0gAygMOnEKF3JlcGVhdGVkZ3JvdXBfZXh0ZW5z" + 
-        "aW9uEiQucHJvdG9idWZfdW5pdHRlc3QuVGVzdEFsbEV4dGVuc2lvbnMYLiAD" + 
-        "KAoyKi5wcm90b2J1Zl91bml0dGVzdC5SZXBlYXRlZEdyb3VwX2V4dGVuc2lv" + 
-        "bjp+CiFyZXBlYXRlZF9uZXN0ZWRfbWVzc2FnZV9leHRlbnNpb24SJC5wcm90" + 
-        "b2J1Zl91bml0dGVzdC5UZXN0QWxsRXh0ZW5zaW9ucxgwIAMoCzItLnByb3Rv" + 
-        "YnVmX3VuaXR0ZXN0LlRlc3RBbGxUeXBlcy5OZXN0ZWRNZXNzYWdlOnMKInJl" + 
-        "cGVhdGVkX2ZvcmVpZ25fbWVzc2FnZV9leHRlbnNpb24SJC5wcm90b2J1Zl91" + 
-        "bml0dGVzdC5UZXN0QWxsRXh0ZW5zaW9ucxgxIAMoCzIhLnByb3RvYnVmX3Vu" + 
-        "aXR0ZXN0LkZvcmVpZ25NZXNzYWdlOngKIXJlcGVhdGVkX2ltcG9ydF9tZXNz" + 
-        "YWdlX2V4dGVuc2lvbhIkLnByb3RvYnVmX3VuaXR0ZXN0LlRlc3RBbGxFeHRl" + 
-        "bnNpb25zGDIgAygLMicucHJvdG9idWZfdW5pdHRlc3RfaW1wb3J0LkltcG9y" + 
-        "dE1lc3NhZ2U6eAoecmVwZWF0ZWRfbmVzdGVkX2VudW1fZXh0ZW5zaW9uEiQu" + 
-        "cHJvdG9idWZfdW5pdHRlc3QuVGVzdEFsbEV4dGVuc2lvbnMYMyADKA4yKi5w" + 
-        "cm90b2J1Zl91bml0dGVzdC5UZXN0QWxsVHlwZXMuTmVzdGVkRW51bTptCh9y" + 
-        "ZXBlYXRlZF9mb3JlaWduX2VudW1fZXh0ZW5zaW9uEiQucHJvdG9idWZfdW5p" + 
-        "dHRlc3QuVGVzdEFsbEV4dGVuc2lvbnMYNCADKA4yHi5wcm90b2J1Zl91bml0" + 
-        "dGVzdC5Gb3JlaWduRW51bTpyCh5yZXBlYXRlZF9pbXBvcnRfZW51bV9leHRl" + 
-        "bnNpb24SJC5wcm90b2J1Zl91bml0dGVzdC5UZXN0QWxsRXh0ZW5zaW9ucxg1" + 
-        "IAMoDjIkLnByb3RvYnVmX3VuaXR0ZXN0X2ltcG9ydC5JbXBvcnRFbnVtOlEK" + 
-        "H3JlcGVhdGVkX3N0cmluZ19waWVjZV9leHRlbnNpb24SJC5wcm90b2J1Zl91" + 
-        "bml0dGVzdC5UZXN0QWxsRXh0ZW5zaW9ucxg2IAMoCUICCAI6SQoXcmVwZWF0" + 
-        "ZWRfY29yZF9leHRlbnNpb24SJC5wcm90b2J1Zl91bml0dGVzdC5UZXN0QWxs" + 
-        "RXh0ZW5zaW9ucxg3IAMoCUICCAE6SQoXZGVmYXVsdF9pbnQzMl9leHRlbnNp" + 
-        "b24SJC5wcm90b2J1Zl91bml0dGVzdC5UZXN0QWxsRXh0ZW5zaW9ucxg9IAEo" + 
-        "BToCNDE6SQoXZGVmYXVsdF9pbnQ2NF9leHRlbnNpb24SJC5wcm90b2J1Zl91" + 
-        "bml0dGVzdC5UZXN0QWxsRXh0ZW5zaW9ucxg+IAEoAzoCNDI6SgoYZGVmYXVs" + 
-        "dF91aW50MzJfZXh0ZW5zaW9uEiQucHJvdG9idWZfdW5pdHRlc3QuVGVzdEFs" + 
-        "bEV4dGVuc2lvbnMYPyABKA06AjQzOkoKGGRlZmF1bHRfdWludDY0X2V4dGVu" + 
-        "c2lvbhIkLnByb3RvYnVmX3VuaXR0ZXN0LlRlc3RBbGxFeHRlbnNpb25zGEAg" + 
-        "ASgEOgI0NDpLChhkZWZhdWx0X3NpbnQzMl9leHRlbnNpb24SJC5wcm90b2J1" + 
-        "Zl91bml0dGVzdC5UZXN0QWxsRXh0ZW5zaW9ucxhBIAEoEToDLTQ1OkoKGGRl" + 
-        "ZmF1bHRfc2ludDY0X2V4dGVuc2lvbhIkLnByb3RvYnVmX3VuaXR0ZXN0LlRl" + 
-        "c3RBbGxFeHRlbnNpb25zGEIgASgSOgI0NjpLChlkZWZhdWx0X2ZpeGVkMzJf" + 
-        "ZXh0ZW5zaW9uEiQucHJvdG9idWZfdW5pdHRlc3QuVGVzdEFsbEV4dGVuc2lv" + 
-        "bnMYQyABKAc6AjQ3OksKGWRlZmF1bHRfZml4ZWQ2NF9leHRlbnNpb24SJC5w" + 
-        "cm90b2J1Zl91bml0dGVzdC5UZXN0QWxsRXh0ZW5zaW9ucxhEIAEoBjoCNDg6" + 
-        "TAoaZGVmYXVsdF9zZml4ZWQzMl9leHRlbnNpb24SJC5wcm90b2J1Zl91bml0" + 
-        "dGVzdC5UZXN0QWxsRXh0ZW5zaW9ucxhFIAEoDzoCNDk6TQoaZGVmYXVsdF9z" + 
-        "Zml4ZWQ2NF9leHRlbnNpb24SJC5wcm90b2J1Zl91bml0dGVzdC5UZXN0QWxs" + 
-        "RXh0ZW5zaW9ucxhGIAEoEDoDLTUwOksKF2RlZmF1bHRfZmxvYXRfZXh0ZW5z" + 
-        "aW9uEiQucHJvdG9idWZfdW5pdHRlc3QuVGVzdEFsbEV4dGVuc2lvbnMYRyAB" + 
-        "KAI6BDUxLjU6TQoYZGVmYXVsdF9kb3VibGVfZXh0ZW5zaW9uEiQucHJvdG9i" + 
-        "dWZfdW5pdHRlc3QuVGVzdEFsbEV4dGVuc2lvbnMYSCABKAE6BTUyMDAwOkoK" + 
-        "FmRlZmF1bHRfYm9vbF9leHRlbnNpb24SJC5wcm90b2J1Zl91bml0dGVzdC5U" + 
-        "ZXN0QWxsRXh0ZW5zaW9ucxhJIAEoCDoEdHJ1ZTpNChhkZWZhdWx0X3N0cmlu" + 
-        "Z19leHRlbnNpb24SJC5wcm90b2J1Zl91bml0dGVzdC5UZXN0QWxsRXh0ZW5z" + 
-        "aW9ucxhKIAEoCToFaGVsbG86TAoXZGVmYXVsdF9ieXRlc19leHRlbnNpb24S" + 
-        "JC5wcm90b2J1Zl91bml0dGVzdC5UZXN0QWxsRXh0ZW5zaW9ucxhLIAEoDDoF" + 
-        "d29ybGQ6fAodZGVmYXVsdF9uZXN0ZWRfZW51bV9leHRlbnNpb24SJC5wcm90" + 
-        "b2J1Zl91bml0dGVzdC5UZXN0QWxsRXh0ZW5zaW9ucxhRIAEoDjIqLnByb3Rv" + 
-        "YnVmX3VuaXR0ZXN0LlRlc3RBbGxUeXBlcy5OZXN0ZWRFbnVtOgNCQVI6eQoe" + 
-        "ZGVmYXVsdF9mb3JlaWduX2VudW1fZXh0ZW5zaW9uEiQucHJvdG9idWZfdW5p" + 
-        "dHRlc3QuVGVzdEFsbEV4dGVuc2lvbnMYUiABKA4yHi5wcm90b2J1Zl91bml0" + 
-        "dGVzdC5Gb3JlaWduRW51bToLRk9SRUlHTl9CQVI6fQodZGVmYXVsdF9pbXBv" + 
-        "cnRfZW51bV9leHRlbnNpb24SJC5wcm90b2J1Zl91bml0dGVzdC5UZXN0QWxs" + 
-        "RXh0ZW5zaW9ucxhTIAEoDjIkLnByb3RvYnVmX3VuaXR0ZXN0X2ltcG9ydC5J" + 
-        "bXBvcnRFbnVtOgpJTVBPUlRfQkFSOlUKHmRlZmF1bHRfc3RyaW5nX3BpZWNl" + 
+        "MCADKAsyLS5wcm90b2J1Zl91bml0dGVzdC5UZXN0QWxsVHlwZXMuTmVzdGVk" + 
+        "TWVzc2FnZTpzCiJyZXBlYXRlZF9mb3JlaWduX21lc3NhZ2VfZXh0ZW5zaW9u" + 
+        "EiQucHJvdG9idWZfdW5pdHRlc3QuVGVzdEFsbEV4dGVuc2lvbnMYMSADKAsy" + 
+        "IS5wcm90b2J1Zl91bml0dGVzdC5Gb3JlaWduTWVzc2FnZTp4CiFyZXBlYXRl" + 
+        "ZF9pbXBvcnRfbWVzc2FnZV9leHRlbnNpb24SJC5wcm90b2J1Zl91bml0dGVz" + 
+        "dC5UZXN0QWxsRXh0ZW5zaW9ucxgyIAMoCzInLnByb3RvYnVmX3VuaXR0ZXN0" + 
+        "X2ltcG9ydC5JbXBvcnRNZXNzYWdlOngKHnJlcGVhdGVkX25lc3RlZF9lbnVt" + 
         "X2V4dGVuc2lvbhIkLnByb3RvYnVmX3VuaXR0ZXN0LlRlc3RBbGxFeHRlbnNp" + 
-        "b25zGFQgASgJOgNhYmNCAggCOk0KFmRlZmF1bHRfY29yZF9leHRlbnNpb24S" + 
-        "JC5wcm90b2J1Zl91bml0dGVzdC5UZXN0QWxsRXh0ZW5zaW9ucxhVIAEoCToD" + 
-        "MTIzQgIIATpCChNteV9leHRlbnNpb25fc3RyaW5nEiUucHJvdG9idWZfdW5p" + 
-        "dHRlc3QuVGVzdEZpZWxkT3JkZXJpbmdzGDIgASgJOj8KEG15X2V4dGVuc2lv" + 
-        "bl9pbnQSJS5wcm90b2J1Zl91bml0dGVzdC5UZXN0RmllbGRPcmRlcmluZ3MY" + 
-        "BSABKAVCSkINVW5pdHRlc3RQcm90b0gBwj42CiFHb29nbGUuUHJvdG9jb2xC" + 
-        "dWZmZXJzLlRlc3RQcm90b3MSEVVuaXRUZXN0UHJvdG9GaWxl"),
+        "b25zGDMgAygOMioucHJvdG9idWZfdW5pdHRlc3QuVGVzdEFsbFR5cGVzLk5l" + 
+        "c3RlZEVudW06bQofcmVwZWF0ZWRfZm9yZWlnbl9lbnVtX2V4dGVuc2lvbhIk" + 
+        "LnByb3RvYnVmX3VuaXR0ZXN0LlRlc3RBbGxFeHRlbnNpb25zGDQgAygOMh4u" + 
+        "cHJvdG9idWZfdW5pdHRlc3QuRm9yZWlnbkVudW06cgoecmVwZWF0ZWRfaW1w" + 
+        "b3J0X2VudW1fZXh0ZW5zaW9uEiQucHJvdG9idWZfdW5pdHRlc3QuVGVzdEFs" + 
+        "bEV4dGVuc2lvbnMYNSADKA4yJC5wcm90b2J1Zl91bml0dGVzdF9pbXBvcnQu" + 
+        "SW1wb3J0RW51bTpRCh9yZXBlYXRlZF9zdHJpbmdfcGllY2VfZXh0ZW5zaW9u" + 
+        "EiQucHJvdG9idWZfdW5pdHRlc3QuVGVzdEFsbEV4dGVuc2lvbnMYNiADKAlC" + 
+        "AggCOkkKF3JlcGVhdGVkX2NvcmRfZXh0ZW5zaW9uEiQucHJvdG9idWZfdW5p" + 
+        "dHRlc3QuVGVzdEFsbEV4dGVuc2lvbnMYNyADKAlCAggBOkkKF2RlZmF1bHRf" + 
+        "aW50MzJfZXh0ZW5zaW9uEiQucHJvdG9idWZfdW5pdHRlc3QuVGVzdEFsbEV4" + 
+        "dGVuc2lvbnMYPSABKAU6AjQxOkkKF2RlZmF1bHRfaW50NjRfZXh0ZW5zaW9u" + 
+        "EiQucHJvdG9idWZfdW5pdHRlc3QuVGVzdEFsbEV4dGVuc2lvbnMYPiABKAM6" + 
+        "AjQyOkoKGGRlZmF1bHRfdWludDMyX2V4dGVuc2lvbhIkLnByb3RvYnVmX3Vu" + 
+        "aXR0ZXN0LlRlc3RBbGxFeHRlbnNpb25zGD8gASgNOgI0MzpKChhkZWZhdWx0" + 
+        "X3VpbnQ2NF9leHRlbnNpb24SJC5wcm90b2J1Zl91bml0dGVzdC5UZXN0QWxs" + 
+        "RXh0ZW5zaW9ucxhAIAEoBDoCNDQ6SwoYZGVmYXVsdF9zaW50MzJfZXh0ZW5z" + 
+        "aW9uEiQucHJvdG9idWZfdW5pdHRlc3QuVGVzdEFsbEV4dGVuc2lvbnMYQSAB" + 
+        "KBE6Ay00NTpKChhkZWZhdWx0X3NpbnQ2NF9leHRlbnNpb24SJC5wcm90b2J1" + 
+        "Zl91bml0dGVzdC5UZXN0QWxsRXh0ZW5zaW9ucxhCIAEoEjoCNDY6SwoZZGVm" + 
+        "YXVsdF9maXhlZDMyX2V4dGVuc2lvbhIkLnByb3RvYnVmX3VuaXR0ZXN0LlRl" + 
+        "c3RBbGxFeHRlbnNpb25zGEMgASgHOgI0NzpLChlkZWZhdWx0X2ZpeGVkNjRf" + 
+        "ZXh0ZW5zaW9uEiQucHJvdG9idWZfdW5pdHRlc3QuVGVzdEFsbEV4dGVuc2lv" + 
+        "bnMYRCABKAY6AjQ4OkwKGmRlZmF1bHRfc2ZpeGVkMzJfZXh0ZW5zaW9uEiQu" + 
+        "cHJvdG9idWZfdW5pdHRlc3QuVGVzdEFsbEV4dGVuc2lvbnMYRSABKA86AjQ5" + 
+        "Ok0KGmRlZmF1bHRfc2ZpeGVkNjRfZXh0ZW5zaW9uEiQucHJvdG9idWZfdW5p" + 
+        "dHRlc3QuVGVzdEFsbEV4dGVuc2lvbnMYRiABKBA6Ay01MDpLChdkZWZhdWx0" + 
+        "X2Zsb2F0X2V4dGVuc2lvbhIkLnByb3RvYnVmX3VuaXR0ZXN0LlRlc3RBbGxF" + 
+        "eHRlbnNpb25zGEcgASgCOgQ1MS41Ok0KGGRlZmF1bHRfZG91YmxlX2V4dGVu" + 
+        "c2lvbhIkLnByb3RvYnVmX3VuaXR0ZXN0LlRlc3RBbGxFeHRlbnNpb25zGEgg" + 
+        "ASgBOgU1MjAwMDpKChZkZWZhdWx0X2Jvb2xfZXh0ZW5zaW9uEiQucHJvdG9i" + 
+        "dWZfdW5pdHRlc3QuVGVzdEFsbEV4dGVuc2lvbnMYSSABKAg6BHRydWU6TQoY" + 
+        "ZGVmYXVsdF9zdHJpbmdfZXh0ZW5zaW9uEiQucHJvdG9idWZfdW5pdHRlc3Qu" + 
+        "VGVzdEFsbEV4dGVuc2lvbnMYSiABKAk6BWhlbGxvOkwKF2RlZmF1bHRfYnl0" + 
+        "ZXNfZXh0ZW5zaW9uEiQucHJvdG9idWZfdW5pdHRlc3QuVGVzdEFsbEV4dGVu" + 
+        "c2lvbnMYSyABKAw6BXdvcmxkOnwKHWRlZmF1bHRfbmVzdGVkX2VudW1fZXh0" + 
+        "ZW5zaW9uEiQucHJvdG9idWZfdW5pdHRlc3QuVGVzdEFsbEV4dGVuc2lvbnMY" + 
+        "USABKA4yKi5wcm90b2J1Zl91bml0dGVzdC5UZXN0QWxsVHlwZXMuTmVzdGVk" + 
+        "RW51bToDQkFSOnkKHmRlZmF1bHRfZm9yZWlnbl9lbnVtX2V4dGVuc2lvbhIk" + 
+        "LnByb3RvYnVmX3VuaXR0ZXN0LlRlc3RBbGxFeHRlbnNpb25zGFIgASgOMh4u" + 
+        "cHJvdG9idWZfdW5pdHRlc3QuRm9yZWlnbkVudW06C0ZPUkVJR05fQkFSOn0K" + 
+        "HWRlZmF1bHRfaW1wb3J0X2VudW1fZXh0ZW5zaW9uEiQucHJvdG9idWZfdW5p" + 
+        "dHRlc3QuVGVzdEFsbEV4dGVuc2lvbnMYUyABKA4yJC5wcm90b2J1Zl91bml0" + 
+        "dGVzdF9pbXBvcnQuSW1wb3J0RW51bToKSU1QT1JUX0JBUjpVCh5kZWZhdWx0" + 
+        "X3N0cmluZ19waWVjZV9leHRlbnNpb24SJC5wcm90b2J1Zl91bml0dGVzdC5U" + 
+        "ZXN0QWxsRXh0ZW5zaW9ucxhUIAEoCToDYWJjQgIIAjpNChZkZWZhdWx0X2Nv" + 
+        "cmRfZXh0ZW5zaW9uEiQucHJvdG9idWZfdW5pdHRlc3QuVGVzdEFsbEV4dGVu" + 
+        "c2lvbnMYVSABKAk6AzEyM0ICCAE6QgoTbXlfZXh0ZW5zaW9uX3N0cmluZxIl" + 
+        "LnByb3RvYnVmX3VuaXR0ZXN0LlRlc3RGaWVsZE9yZGVyaW5ncxgyIAEoCTo/" + 
+        "ChBteV9leHRlbnNpb25faW50EiUucHJvdG9idWZfdW5pdHRlc3QuVGVzdEZp" + 
+        "ZWxkT3JkZXJpbmdzGAUgASgFOksKFnBhY2tlZF9pbnQzMl9leHRlbnNpb24S" + 
+        "Jy5wcm90b2J1Zl91bml0dGVzdC5UZXN0UGFja2VkRXh0ZW5zaW9ucxhaIAMo" + 
+        "BUICEAE6SwoWcGFja2VkX2ludDY0X2V4dGVuc2lvbhInLnByb3RvYnVmX3Vu" + 
+        "aXR0ZXN0LlRlc3RQYWNrZWRFeHRlbnNpb25zGFsgAygDQgIQATpMChdwYWNr" + 
+        "ZWRfdWludDMyX2V4dGVuc2lvbhInLnByb3RvYnVmX3VuaXR0ZXN0LlRlc3RQ" + 
+        "YWNrZWRFeHRlbnNpb25zGFwgAygNQgIQATpMChdwYWNrZWRfdWludDY0X2V4" + 
+        "dGVuc2lvbhInLnByb3RvYnVmX3VuaXR0ZXN0LlRlc3RQYWNrZWRFeHRlbnNp" + 
+        "b25zGF0gAygEQgIQATpMChdwYWNrZWRfc2ludDMyX2V4dGVuc2lvbhInLnBy" + 
+        "b3RvYnVmX3VuaXR0ZXN0LlRlc3RQYWNrZWRFeHRlbnNpb25zGF4gAygRQgIQ" + 
+        "ATpMChdwYWNrZWRfc2ludDY0X2V4dGVuc2lvbhInLnByb3RvYnVmX3VuaXR0" + 
+        "ZXN0LlRlc3RQYWNrZWRFeHRlbnNpb25zGF8gAygSQgIQATpNChhwYWNrZWRf" + 
+        "Zml4ZWQzMl9leHRlbnNpb24SJy5wcm90b2J1Zl91bml0dGVzdC5UZXN0UGFj" + 
+        "a2VkRXh0ZW5zaW9ucxhgIAMoB0ICEAE6TQoYcGFja2VkX2ZpeGVkNjRfZXh0" + 
+        "ZW5zaW9uEicucHJvdG9idWZfdW5pdHRlc3QuVGVzdFBhY2tlZEV4dGVuc2lv" + 
+        "bnMYYSADKAZCAhABOk4KGXBhY2tlZF9zZml4ZWQzMl9leHRlbnNpb24SJy5w" + 
+        "cm90b2J1Zl91bml0dGVzdC5UZXN0UGFja2VkRXh0ZW5zaW9ucxhiIAMoD0IC" + 
+        "EAE6TgoZcGFja2VkX3NmaXhlZDY0X2V4dGVuc2lvbhInLnByb3RvYnVmX3Vu" + 
+        "aXR0ZXN0LlRlc3RQYWNrZWRFeHRlbnNpb25zGGMgAygQQgIQATpLChZwYWNr" + 
+        "ZWRfZmxvYXRfZXh0ZW5zaW9uEicucHJvdG9idWZfdW5pdHRlc3QuVGVzdFBh" + 
+        "Y2tlZEV4dGVuc2lvbnMYZCADKAJCAhABOkwKF3BhY2tlZF9kb3VibGVfZXh0" + 
+        "ZW5zaW9uEicucHJvdG9idWZfdW5pdHRlc3QuVGVzdFBhY2tlZEV4dGVuc2lv" + 
+        "bnMYZSADKAFCAhABOkoKFXBhY2tlZF9ib29sX2V4dGVuc2lvbhInLnByb3Rv" + 
+        "YnVmX3VuaXR0ZXN0LlRlc3RQYWNrZWRFeHRlbnNpb25zGGYgAygIQgIQATpq" + 
+        "ChVwYWNrZWRfZW51bV9leHRlbnNpb24SJy5wcm90b2J1Zl91bml0dGVzdC5U" + 
+        "ZXN0UGFja2VkRXh0ZW5zaW9ucxhnIAMoDjIeLnByb3RvYnVmX3VuaXR0ZXN0" + 
+        "LkZvcmVpZ25FbnVtQgIQAUJKQg1Vbml0dGVzdFByb3RvSAHCPjYKIUdvb2ds" + 
+        "ZS5Qcm90b2NvbEJ1ZmZlcnMuVGVzdFByb3RvcxIRVW5pdFRlc3RQcm90b0Zp" + 
+        "bGU="),
         new pbd::FileDescriptor[] {
           global::Google.ProtocolBuffers.DescriptorProtos.CSharpOptions.Descriptor, 
           global::Google.ProtocolBuffers.TestProtos.UnitTestImportProtoFile.Descriptor, 
@@ -457,6 +493,48 @@ namespace Google.ProtocolBuffers.TestProtos {
         pb::GeneratedSingleExtension<string>.CreateInstance(Descriptor.Extensions[68]);
     public static readonly pb::GeneratedExtensionBase<int> MyExtensionInt =
         pb::GeneratedSingleExtension<int>.CreateInstance(Descriptor.Extensions[69]);
+    public static readonly
+        pb::GeneratedExtensionBase<scg::IList<int>> PackedInt32Extension =
+        pb::GeneratedRepeatExtension<int>.CreateInstance(Descriptor.Extensions[70]);
+    public static readonly
+        pb::GeneratedExtensionBase<scg::IList<long>> PackedInt64Extension =
+        pb::GeneratedRepeatExtension<long>.CreateInstance(Descriptor.Extensions[71]);
+    public static readonly
+        pb::GeneratedExtensionBase<scg::IList<uint>> PackedUint32Extension =
+        pb::GeneratedRepeatExtension<uint>.CreateInstance(Descriptor.Extensions[72]);
+    public static readonly
+        pb::GeneratedExtensionBase<scg::IList<ulong>> PackedUint64Extension =
+        pb::GeneratedRepeatExtension<ulong>.CreateInstance(Descriptor.Extensions[73]);
+    public static readonly
+        pb::GeneratedExtensionBase<scg::IList<int>> PackedSint32Extension =
+        pb::GeneratedRepeatExtension<int>.CreateInstance(Descriptor.Extensions[74]);
+    public static readonly
+        pb::GeneratedExtensionBase<scg::IList<long>> PackedSint64Extension =
+        pb::GeneratedRepeatExtension<long>.CreateInstance(Descriptor.Extensions[75]);
+    public static readonly
+        pb::GeneratedExtensionBase<scg::IList<uint>> PackedFixed32Extension =
+        pb::GeneratedRepeatExtension<uint>.CreateInstance(Descriptor.Extensions[76]);
+    public static readonly
+        pb::GeneratedExtensionBase<scg::IList<ulong>> PackedFixed64Extension =
+        pb::GeneratedRepeatExtension<ulong>.CreateInstance(Descriptor.Extensions[77]);
+    public static readonly
+        pb::GeneratedExtensionBase<scg::IList<int>> PackedSfixed32Extension =
+        pb::GeneratedRepeatExtension<int>.CreateInstance(Descriptor.Extensions[78]);
+    public static readonly
+        pb::GeneratedExtensionBase<scg::IList<long>> PackedSfixed64Extension =
+        pb::GeneratedRepeatExtension<long>.CreateInstance(Descriptor.Extensions[79]);
+    public static readonly
+        pb::GeneratedExtensionBase<scg::IList<float>> PackedFloatExtension =
+        pb::GeneratedRepeatExtension<float>.CreateInstance(Descriptor.Extensions[80]);
+    public static readonly
+        pb::GeneratedExtensionBase<scg::IList<double>> PackedDoubleExtension =
+        pb::GeneratedRepeatExtension<double>.CreateInstance(Descriptor.Extensions[81]);
+    public static readonly
+        pb::GeneratedExtensionBase<scg::IList<bool>> PackedBoolExtension =
+        pb::GeneratedRepeatExtension<bool>.CreateInstance(Descriptor.Extensions[82]);
+    public static readonly
+        pb::GeneratedExtensionBase<scg::IList<global::Google.ProtocolBuffers.TestProtos.ForeignEnum>> PackedEnumExtension =
+        pb::GeneratedRepeatExtension<global::Google.ProtocolBuffers.TestProtos.ForeignEnum>.CreateInstance(Descriptor.Extensions[83]);
     #endregion
     
     #region Static variables
@@ -585,23 +663,33 @@ namespace Google.ProtocolBuffers.TestProtos {
     internal static pb::FieldAccess.FieldAccessorTable<global::Google.ProtocolBuffers.TestProtos.TestExtremeDefaultValues, global::Google.ProtocolBuffers.TestProtos.TestExtremeDefaultValues.Builder> internal__static_protobuf_unittest_TestExtremeDefaultValues__FieldAccessorTable
         = new pb::FieldAccess.FieldAccessorTable<global::Google.ProtocolBuffers.TestProtos.TestExtremeDefaultValues, global::Google.ProtocolBuffers.TestProtos.TestExtremeDefaultValues.Builder>(internal__static_protobuf_unittest_TestExtremeDefaultValues__Descriptor,
             new string[] { "EscapedBytes", "LargeUint32", "LargeUint64", "SmallInt32", "SmallInt64", "Utf8String", });
-    internal static readonly pbd::MessageDescriptor internal__static_protobuf_unittest_FooRequest__Descriptor
+    internal static readonly pbd::MessageDescriptor internal__static_protobuf_unittest_TestPackedTypes__Descriptor
         = Descriptor.MessageTypes[19];
+    internal static pb::FieldAccess.FieldAccessorTable<global::Google.ProtocolBuffers.TestProtos.TestPackedTypes, global::Google.ProtocolBuffers.TestProtos.TestPackedTypes.Builder> internal__static_protobuf_unittest_TestPackedTypes__FieldAccessorTable
+        = new pb::FieldAccess.FieldAccessorTable<global::Google.ProtocolBuffers.TestProtos.TestPackedTypes, global::Google.ProtocolBuffers.TestProtos.TestPackedTypes.Builder>(internal__static_protobuf_unittest_TestPackedTypes__Descriptor,
+            new string[] { "PackedInt32", "PackedInt64", "PackedUint32", "PackedUint64", "PackedSint32", "PackedSint64", "PackedFixed32", "PackedFixed64", "PackedSfixed32", "PackedSfixed64", "PackedFloat", "PackedDouble", "PackedBool", "PackedEnum", });
+    internal static readonly pbd::MessageDescriptor internal__static_protobuf_unittest_TestPackedExtensions__Descriptor
+        = Descriptor.MessageTypes[20];
+    internal static pb::FieldAccess.FieldAccessorTable<global::Google.ProtocolBuffers.TestProtos.TestPackedExtensions, global::Google.ProtocolBuffers.TestProtos.TestPackedExtensions.Builder> internal__static_protobuf_unittest_TestPackedExtensions__FieldAccessorTable
+        = new pb::FieldAccess.FieldAccessorTable<global::Google.ProtocolBuffers.TestProtos.TestPackedExtensions, global::Google.ProtocolBuffers.TestProtos.TestPackedExtensions.Builder>(internal__static_protobuf_unittest_TestPackedExtensions__Descriptor,
+            new string[] { });
+    internal static readonly pbd::MessageDescriptor internal__static_protobuf_unittest_FooRequest__Descriptor
+        = Descriptor.MessageTypes[21];
     internal static pb::FieldAccess.FieldAccessorTable<global::Google.ProtocolBuffers.TestProtos.FooRequest, global::Google.ProtocolBuffers.TestProtos.FooRequest.Builder> internal__static_protobuf_unittest_FooRequest__FieldAccessorTable
         = new pb::FieldAccess.FieldAccessorTable<global::Google.ProtocolBuffers.TestProtos.FooRequest, global::Google.ProtocolBuffers.TestProtos.FooRequest.Builder>(internal__static_protobuf_unittest_FooRequest__Descriptor,
             new string[] { });
     internal static readonly pbd::MessageDescriptor internal__static_protobuf_unittest_FooResponse__Descriptor
-        = Descriptor.MessageTypes[20];
+        = Descriptor.MessageTypes[22];
     internal static pb::FieldAccess.FieldAccessorTable<global::Google.ProtocolBuffers.TestProtos.FooResponse, global::Google.ProtocolBuffers.TestProtos.FooResponse.Builder> internal__static_protobuf_unittest_FooResponse__FieldAccessorTable
         = new pb::FieldAccess.FieldAccessorTable<global::Google.ProtocolBuffers.TestProtos.FooResponse, global::Google.ProtocolBuffers.TestProtos.FooResponse.Builder>(internal__static_protobuf_unittest_FooResponse__Descriptor,
             new string[] { });
     internal static readonly pbd::MessageDescriptor internal__static_protobuf_unittest_BarRequest__Descriptor
-        = Descriptor.MessageTypes[21];
+        = Descriptor.MessageTypes[23];
     internal static pb::FieldAccess.FieldAccessorTable<global::Google.ProtocolBuffers.TestProtos.BarRequest, global::Google.ProtocolBuffers.TestProtos.BarRequest.Builder> internal__static_protobuf_unittest_BarRequest__FieldAccessorTable
         = new pb::FieldAccess.FieldAccessorTable<global::Google.ProtocolBuffers.TestProtos.BarRequest, global::Google.ProtocolBuffers.TestProtos.BarRequest.Builder>(internal__static_protobuf_unittest_BarRequest__Descriptor,
             new string[] { });
     internal static readonly pbd::MessageDescriptor internal__static_protobuf_unittest_BarResponse__Descriptor
-        = Descriptor.MessageTypes[22];
+        = Descriptor.MessageTypes[24];
     internal static pb::FieldAccess.FieldAccessorTable<global::Google.ProtocolBuffers.TestProtos.BarResponse, global::Google.ProtocolBuffers.TestProtos.BarResponse.Builder> internal__static_protobuf_unittest_BarResponse__FieldAccessorTable
         = new pb::FieldAccess.FieldAccessorTable<global::Google.ProtocolBuffers.TestProtos.BarResponse, global::Google.ProtocolBuffers.TestProtos.BarResponse.Builder>(internal__static_protobuf_unittest_BarResponse__Descriptor,
             new string[] { });
@@ -1983,50 +2071,80 @@ namespace Google.ProtocolBuffers.TestProtos {
       if (HasOptionalCord) {
         output.WriteString(25, OptionalCord);
       }
-      foreach (int element in RepeatedInt32List) {
-        output.WriteInt32(31, element);
+      if (repeatedInt32_.Count > 0) {
+        foreach (int element in repeatedInt32_) {
+          output.WriteInt32(31, element);
+        }
       }
-      foreach (long element in RepeatedInt64List) {
-        output.WriteInt64(32, element);
+      if (repeatedInt64_.Count > 0) {
+        foreach (long element in repeatedInt64_) {
+          output.WriteInt64(32, element);
+        }
       }
-      foreach (uint element in RepeatedUint32List) {
-        output.WriteUInt32(33, element);
+      if (repeatedUint32_.Count > 0) {
+        foreach (uint element in repeatedUint32_) {
+          output.WriteUInt32(33, element);
+        }
       }
-      foreach (ulong element in RepeatedUint64List) {
-        output.WriteUInt64(34, element);
+      if (repeatedUint64_.Count > 0) {
+        foreach (ulong element in repeatedUint64_) {
+          output.WriteUInt64(34, element);
+        }
       }
-      foreach (int element in RepeatedSint32List) {
-        output.WriteSInt32(35, element);
+      if (repeatedSint32_.Count > 0) {
+        foreach (int element in repeatedSint32_) {
+          output.WriteSInt32(35, element);
+        }
       }
-      foreach (long element in RepeatedSint64List) {
-        output.WriteSInt64(36, element);
+      if (repeatedSint64_.Count > 0) {
+        foreach (long element in repeatedSint64_) {
+          output.WriteSInt64(36, element);
+        }
       }
-      foreach (uint element in RepeatedFixed32List) {
-        output.WriteFixed32(37, element);
+      if (repeatedFixed32_.Count > 0) {
+        foreach (uint element in repeatedFixed32_) {
+          output.WriteFixed32(37, element);
+        }
       }
-      foreach (ulong element in RepeatedFixed64List) {
-        output.WriteFixed64(38, element);
+      if (repeatedFixed64_.Count > 0) {
+        foreach (ulong element in repeatedFixed64_) {
+          output.WriteFixed64(38, element);
+        }
       }
-      foreach (int element in RepeatedSfixed32List) {
-        output.WriteSFixed32(39, element);
+      if (repeatedSfixed32_.Count > 0) {
+        foreach (int element in repeatedSfixed32_) {
+          output.WriteSFixed32(39, element);
+        }
       }
-      foreach (long element in RepeatedSfixed64List) {
-        output.WriteSFixed64(40, element);
+      if (repeatedSfixed64_.Count > 0) {
+        foreach (long element in repeatedSfixed64_) {
+          output.WriteSFixed64(40, element);
+        }
       }
-      foreach (float element in RepeatedFloatList) {
-        output.WriteFloat(41, element);
+      if (repeatedFloat_.Count > 0) {
+        foreach (float element in repeatedFloat_) {
+          output.WriteFloat(41, element);
+        }
       }
-      foreach (double element in RepeatedDoubleList) {
-        output.WriteDouble(42, element);
+      if (repeatedDouble_.Count > 0) {
+        foreach (double element in repeatedDouble_) {
+          output.WriteDouble(42, element);
+        }
       }
-      foreach (bool element in RepeatedBoolList) {
-        output.WriteBool(43, element);
+      if (repeatedBool_.Count > 0) {
+        foreach (bool element in repeatedBool_) {
+          output.WriteBool(43, element);
+        }
       }
-      foreach (string element in RepeatedStringList) {
-        output.WriteString(44, element);
+      if (repeatedString_.Count > 0) {
+        foreach (string element in repeatedString_) {
+          output.WriteString(44, element);
+        }
       }
-      foreach (pb::ByteString element in RepeatedBytesList) {
-        output.WriteBytes(45, element);
+      if (repeatedBytes_.Count > 0) {
+        foreach (pb::ByteString element in repeatedBytes_) {
+          output.WriteBytes(45, element);
+        }
       }
       foreach (global::Google.ProtocolBuffers.TestProtos.TestAllTypes.Types.RepeatedGroup element in RepeatedGroupList) {
         output.WriteGroup(46, element);
@@ -2040,20 +2158,30 @@ namespace Google.ProtocolBuffers.TestProtos {
       foreach (global::Google.ProtocolBuffers.TestProtos.ImportMessage element in RepeatedImportMessageList) {
         output.WriteMessage(50, element);
       }
-      foreach (global::Google.ProtocolBuffers.TestProtos.TestAllTypes.Types.NestedEnum element in RepeatedNestedEnumList) {
-        output.WriteEnum(51, (int) element);
+      if (repeatedNestedEnum_.Count > 0) {
+        foreach (int element in repeatedNestedEnum_) {
+          output.WriteEnum(51, element);
+        }
       }
-      foreach (global::Google.ProtocolBuffers.TestProtos.ForeignEnum element in RepeatedForeignEnumList) {
-        output.WriteEnum(52, (int) element);
+      if (repeatedForeignEnum_.Count > 0) {
+        foreach (int element in repeatedForeignEnum_) {
+          output.WriteEnum(52, element);
+        }
       }
-      foreach (global::Google.ProtocolBuffers.TestProtos.ImportEnum element in RepeatedImportEnumList) {
-        output.WriteEnum(53, (int) element);
+      if (repeatedImportEnum_.Count > 0) {
+        foreach (int element in repeatedImportEnum_) {
+          output.WriteEnum(53, element);
+        }
       }
-      foreach (string element in RepeatedStringPieceList) {
-        output.WriteString(54, element);
+      if (repeatedStringPiece_.Count > 0) {
+        foreach (string element in repeatedStringPiece_) {
+          output.WriteString(54, element);
+        }
       }
-      foreach (string element in RepeatedCordList) {
-        output.WriteString(55, element);
+      if (repeatedCord_.Count > 0) {
+        foreach (string element in repeatedCord_) {
+          output.WriteString(55, element);
+        }
       }
       if (HasDefaultInt32) {
         output.WriteInt32(61, DefaultInt32);
@@ -2197,50 +2325,111 @@ namespace Google.ProtocolBuffers.TestProtos {
         if (HasOptionalCord) {
           size += pb::CodedOutputStream.ComputeStringSize(25, OptionalCord);
         }
-        foreach (int element in RepeatedInt32List) {
-          size += pb::CodedOutputStream.ComputeInt32Size(31, element);
-        }
-        foreach (long element in RepeatedInt64List) {
-          size += pb::CodedOutputStream.ComputeInt64Size(32, element);
-        }
-        foreach (uint element in RepeatedUint32List) {
-          size += pb::CodedOutputStream.ComputeUInt32Size(33, element);
-        }
-        foreach (ulong element in RepeatedUint64List) {
-          size += pb::CodedOutputStream.ComputeUInt64Size(34, element);
-        }
-        foreach (int element in RepeatedSint32List) {
-          size += pb::CodedOutputStream.ComputeSInt32Size(35, element);
-        }
-        foreach (long element in RepeatedSint64List) {
-          size += pb::CodedOutputStream.ComputeSInt64Size(36, element);
-        }
-        foreach (uint element in RepeatedFixed32List) {
-          size += pb::CodedOutputStream.ComputeFixed32Size(37, element);
-        }
-        foreach (ulong element in RepeatedFixed64List) {
-          size += pb::CodedOutputStream.ComputeFixed64Size(38, element);
-        }
-        foreach (int element in RepeatedSfixed32List) {
-          size += pb::CodedOutputStream.ComputeSFixed32Size(39, element);
-        }
-        foreach (long element in RepeatedSfixed64List) {
-          size += pb::CodedOutputStream.ComputeSFixed64Size(40, element);
-        }
-        foreach (float element in RepeatedFloatList) {
-          size += pb::CodedOutputStream.ComputeFloatSize(41, element);
-        }
-        foreach (double element in RepeatedDoubleList) {
-          size += pb::CodedOutputStream.ComputeDoubleSize(42, element);
-        }
-        foreach (bool element in RepeatedBoolList) {
-          size += pb::CodedOutputStream.ComputeBoolSize(43, element);
-        }
-        foreach (string element in RepeatedStringList) {
-          size += pb::CodedOutputStream.ComputeStringSize(44, element);
-        }
-        foreach (pb::ByteString element in RepeatedBytesList) {
-          size += pb::CodedOutputStream.ComputeBytesSize(45, element);
+        {
+          int dataSize = 0;
+          foreach (int element in RepeatedInt32List) {
+            dataSize += pb::CodedOutputStream.ComputeInt32SizeNoTag(element);
+          }
+          size += dataSize;
+          size += 2 * repeatedInt32_.Count;
+        }
+        {
+          int dataSize = 0;
+          foreach (long element in RepeatedInt64List) {
+            dataSize += pb::CodedOutputStream.ComputeInt64SizeNoTag(element);
+          }
+          size += dataSize;
+          size += 2 * repeatedInt64_.Count;
+        }
+        {
+          int dataSize = 0;
+          foreach (uint element in RepeatedUint32List) {
+            dataSize += pb::CodedOutputStream.ComputeUInt32SizeNoTag(element);
+          }
+          size += dataSize;
+          size += 2 * repeatedUint32_.Count;
+        }
+        {
+          int dataSize = 0;
+          foreach (ulong element in RepeatedUint64List) {
+            dataSize += pb::CodedOutputStream.ComputeUInt64SizeNoTag(element);
+          }
+          size += dataSize;
+          size += 2 * repeatedUint64_.Count;
+        }
+        {
+          int dataSize = 0;
+          foreach (int element in RepeatedSint32List) {
+            dataSize += pb::CodedOutputStream.ComputeSInt32SizeNoTag(element);
+          }
+          size += dataSize;
+          size += 2 * repeatedSint32_.Count;
+        }
+        {
+          int dataSize = 0;
+          foreach (long element in RepeatedSint64List) {
+            dataSize += pb::CodedOutputStream.ComputeSInt64SizeNoTag(element);
+          }
+          size += dataSize;
+          size += 2 * repeatedSint64_.Count;
+        }
+        {
+          int dataSize = 0;
+          dataSize = 4 * repeatedFixed32_.Count;
+          size += dataSize;
+          size += 2 * repeatedFixed32_.Count;
+        }
+        {
+          int dataSize = 0;
+          dataSize = 8 * repeatedFixed64_.Count;
+          size += dataSize;
+          size += 2 * repeatedFixed64_.Count;
+        }
+        {
+          int dataSize = 0;
+          dataSize = 4 * repeatedSfixed32_.Count;
+          size += dataSize;
+          size += 2 * repeatedSfixed32_.Count;
+        }
+        {
+          int dataSize = 0;
+          dataSize = 8 * repeatedSfixed64_.Count;
+          size += dataSize;
+          size += 2 * repeatedSfixed64_.Count;
+        }
+        {
+          int dataSize = 0;
+          dataSize = 4 * repeatedFloat_.Count;
+          size += dataSize;
+          size += 2 * repeatedFloat_.Count;
+        }
+        {
+          int dataSize = 0;
+          dataSize = 8 * repeatedDouble_.Count;
+          size += dataSize;
+          size += 2 * repeatedDouble_.Count;
+        }
+        {
+          int dataSize = 0;
+          dataSize = 1 * repeatedBool_.Count;
+          size += dataSize;
+          size += 2 * repeatedBool_.Count;
+        }
+        {
+          int dataSize = 0;
+          foreach (string element in RepeatedStringList) {
+            dataSize += pb::CodedOutputStream.ComputeStringSizeNoTag(element);
+          }
+          size += dataSize;
+          size += 2 * repeatedString_.Count;
+        }
+        {
+          int dataSize = 0;
+          foreach (pb::ByteString element in RepeatedBytesList) {
+            dataSize += pb::CodedOutputStream.ComputeBytesSizeNoTag(element);
+          }
+          size += dataSize;
+          size += 2 * repeatedBytes_.Count;
         }
         foreach (global::Google.ProtocolBuffers.TestProtos.TestAllTypes.Types.RepeatedGroup element in RepeatedGroupList) {
           size += pb::CodedOutputStream.ComputeGroupSize(46, element);
@@ -2254,20 +2443,51 @@ namespace Google.ProtocolBuffers.TestProtos {
         foreach (global::Google.ProtocolBuffers.TestProtos.ImportMessage element in RepeatedImportMessageList) {
           size += pb::CodedOutputStream.ComputeMessageSize(50, element);
         }
-        foreach (global::Google.ProtocolBuffers.TestProtos.TestAllTypes.Types.NestedEnum element in RepeatedNestedEnumList) {
-          size += pb::CodedOutputStream.ComputeEnumSize(51, (int) element);
+        {
+          int dataSize = 0;
+          if (repeatedNestedEnum_.Count > 0) {
+            foreach (global::Google.ProtocolBuffers.TestProtos.TestAllTypes.Types.NestedEnum element in repeatedNestedEnum_) {
+              dataSize += pb::CodedOutputStream.ComputeEnumSizeNoTag((int) element);
+            }
+            size += dataSize;
+            size += 2 * repeatedNestedEnum_.Count;
+          }
         }
-        foreach (global::Google.ProtocolBuffers.TestProtos.ForeignEnum element in RepeatedForeignEnumList) {
-          size += pb::CodedOutputStream.ComputeEnumSize(52, (int) element);
+        {
+          int dataSize = 0;
+          if (repeatedForeignEnum_.Count > 0) {
+            foreach (global::Google.ProtocolBuffers.TestProtos.ForeignEnum element in repeatedForeignEnum_) {
+              dataSize += pb::CodedOutputStream.ComputeEnumSizeNoTag((int) element);
+            }
+            size += dataSize;
+            size += 2 * repeatedForeignEnum_.Count;
+          }
         }
-        foreach (global::Google.ProtocolBuffers.TestProtos.ImportEnum element in RepeatedImportEnumList) {
-          size += pb::CodedOutputStream.ComputeEnumSize(53, (int) element);
+        {
+          int dataSize = 0;
+          if (repeatedImportEnum_.Count > 0) {
+            foreach (global::Google.ProtocolBuffers.TestProtos.ImportEnum element in repeatedImportEnum_) {
+              dataSize += pb::CodedOutputStream.ComputeEnumSizeNoTag((int) element);
+            }
+            size += dataSize;
+            size += 2 * repeatedImportEnum_.Count;
+          }
         }
-        foreach (string element in RepeatedStringPieceList) {
-          size += pb::CodedOutputStream.ComputeStringSize(54, element);
+        {
+          int dataSize = 0;
+          foreach (string element in RepeatedStringPieceList) {
+            dataSize += pb::CodedOutputStream.ComputeStringSizeNoTag(element);
+          }
+          size += dataSize;
+          size += 2 * repeatedStringPiece_.Count;
         }
-        foreach (string element in RepeatedCordList) {
-          size += pb::CodedOutputStream.ComputeStringSize(55, element);
+        {
+          int dataSize = 0;
+          foreach (string element in RepeatedCordList) {
+            dataSize += pb::CodedOutputStream.ComputeStringSizeNoTag(element);
+          }
+          size += dataSize;
+          size += 2 * repeatedCord_.Count;
         }
         if (HasDefaultInt32) {
           size += pb::CodedOutputStream.ComputeInt32Size(61, DefaultInt32);
@@ -9369,8 +9589,10 @@ namespace Google.ProtocolBuffers.TestProtos {
         }
         
         public override void WriteTo(pb::CodedOutputStream output) {
-          foreach (int element in NestedmessageRepeatedInt32List) {
-            output.WriteInt32(1, element);
+          if (nestedmessageRepeatedInt32_.Count > 0) {
+            foreach (int element in nestedmessageRepeatedInt32_) {
+              output.WriteInt32(1, element);
+            }
           }
           foreach (global::Google.ProtocolBuffers.TestProtos.ForeignMessage element in NestedmessageRepeatedForeignmessageList) {
             output.WriteMessage(2, element);
@@ -9385,8 +9607,13 @@ namespace Google.ProtocolBuffers.TestProtos {
             if (size != -1) return size;
             
             size = 0;
-            foreach (int element in NestedmessageRepeatedInt32List) {
-              size += pb::CodedOutputStream.ComputeInt32Size(1, element);
+            {
+              int dataSize = 0;
+              foreach (int element in NestedmessageRepeatedInt32List) {
+                dataSize += pb::CodedOutputStream.ComputeInt32SizeNoTag(element);
+              }
+              size += dataSize;
+              size += 1 * nestedmessageRepeatedInt32_.Count;
             }
             foreach (global::Google.ProtocolBuffers.TestProtos.ForeignMessage element in NestedmessageRepeatedForeignmessageList) {
               size += pb::CodedOutputStream.ComputeMessageSize(2, element);
@@ -9949,23 +10176,33 @@ namespace Google.ProtocolBuffers.TestProtos {
       if (HasCordField) {
         output.WriteString(6, CordField);
       }
-      foreach (int element in RepeatedPrimitiveFieldList) {
-        output.WriteInt32(7, element);
+      if (repeatedPrimitiveField_.Count > 0) {
+        foreach (int element in repeatedPrimitiveField_) {
+          output.WriteInt32(7, element);
+        }
       }
-      foreach (string element in RepeatedStringFieldList) {
-        output.WriteString(8, element);
+      if (repeatedStringField_.Count > 0) {
+        foreach (string element in repeatedStringField_) {
+          output.WriteString(8, element);
+        }
       }
-      foreach (global::Google.ProtocolBuffers.TestProtos.ForeignEnum element in RepeatedEnumFieldList) {
-        output.WriteEnum(9, (int) element);
+      if (repeatedEnumField_.Count > 0) {
+        foreach (int element in repeatedEnumField_) {
+          output.WriteEnum(9, element);
+        }
       }
       foreach (global::Google.ProtocolBuffers.TestProtos.ForeignMessage element in RepeatedMessageFieldList) {
         output.WriteMessage(10, element);
       }
-      foreach (string element in RepeatedStringPieceFieldList) {
-        output.WriteString(11, element);
+      if (repeatedStringPieceField_.Count > 0) {
+        foreach (string element in repeatedStringPieceField_) {
+          output.WriteString(11, element);
+        }
       }
-      foreach (string element in RepeatedCordFieldList) {
-        output.WriteString(12, element);
+      if (repeatedCordField_.Count > 0) {
+        foreach (string element in repeatedCordField_) {
+          output.WriteString(12, element);
+        }
       }
       UnknownFields.WriteTo(output);
     }
@@ -9995,23 +10232,50 @@ namespace Google.ProtocolBuffers.TestProtos {
         if (HasCordField) {
           size += pb::CodedOutputStream.ComputeStringSize(6, CordField);
         }
-        foreach (int element in RepeatedPrimitiveFieldList) {
-          size += pb::CodedOutputStream.ComputeInt32Size(7, element);
+        {
+          int dataSize = 0;
+          foreach (int element in RepeatedPrimitiveFieldList) {
+            dataSize += pb::CodedOutputStream.ComputeInt32SizeNoTag(element);
+          }
+          size += dataSize;
+          size += 1 * repeatedPrimitiveField_.Count;
         }
-        foreach (string element in RepeatedStringFieldList) {
-          size += pb::CodedOutputStream.ComputeStringSize(8, element);
+        {
+          int dataSize = 0;
+          foreach (string element in RepeatedStringFieldList) {
+            dataSize += pb::CodedOutputStream.ComputeStringSizeNoTag(element);
+          }
+          size += dataSize;
+          size += 1 * repeatedStringField_.Count;
         }
-        foreach (global::Google.ProtocolBuffers.TestProtos.ForeignEnum element in RepeatedEnumFieldList) {
-          size += pb::CodedOutputStream.ComputeEnumSize(9, (int) element);
+        {
+          int dataSize = 0;
+          if (repeatedEnumField_.Count > 0) {
+            foreach (global::Google.ProtocolBuffers.TestProtos.ForeignEnum element in repeatedEnumField_) {
+              dataSize += pb::CodedOutputStream.ComputeEnumSizeNoTag((int) element);
+            }
+            size += dataSize;
+            size += 1 * repeatedEnumField_.Count;
+          }
         }
         foreach (global::Google.ProtocolBuffers.TestProtos.ForeignMessage element in RepeatedMessageFieldList) {
           size += pb::CodedOutputStream.ComputeMessageSize(10, element);
         }
-        foreach (string element in RepeatedStringPieceFieldList) {
-          size += pb::CodedOutputStream.ComputeStringSize(11, element);
+        {
+          int dataSize = 0;
+          foreach (string element in RepeatedStringPieceFieldList) {
+            dataSize += pb::CodedOutputStream.ComputeStringSizeNoTag(element);
+          }
+          size += dataSize;
+          size += 1 * repeatedStringPieceField_.Count;
         }
-        foreach (string element in RepeatedCordFieldList) {
-          size += pb::CodedOutputStream.ComputeStringSize(12, element);
+        {
+          int dataSize = 0;
+          foreach (string element in RepeatedCordFieldList) {
+            dataSize += pb::CodedOutputStream.ComputeStringSizeNoTag(element);
+          }
+          size += dataSize;
+          size += 1 * repeatedCordField_.Count;
         }
         size += UnknownFields.SerializedSize;
         memoizedSerializedSize = size;
@@ -11209,6 +11473,1260 @@ namespace Google.ProtocolBuffers.TestProtos {
     }
   }
   
+  public sealed partial class TestPackedTypes : pb::GeneratedMessage<TestPackedTypes, TestPackedTypes.Builder> {
+    private static readonly TestPackedTypes defaultInstance = new Builder().BuildPartial();
+    public static TestPackedTypes DefaultInstance {
+      get { return defaultInstance; }
+    }
+    
+    public override TestPackedTypes DefaultInstanceForType {
+      get { return defaultInstance; }
+    }
+    
+    protected override TestPackedTypes ThisMessage {
+      get { return this; }
+    }
+    
+    public static pbd::MessageDescriptor Descriptor {
+      get { return global::Google.ProtocolBuffers.TestProtos.UnitTestProtoFile.internal__static_protobuf_unittest_TestPackedTypes__Descriptor; }
+    }
+    
+    protected override pb::FieldAccess.FieldAccessorTable<TestPackedTypes, TestPackedTypes.Builder> InternalFieldAccessors {
+      get { return global::Google.ProtocolBuffers.TestProtos.UnitTestProtoFile.internal__static_protobuf_unittest_TestPackedTypes__FieldAccessorTable; }
+    }
+    
+    private int packedInt32MemoizedSerializedSize;
+    private pbc::PopsicleList<int> packedInt32_ = new pbc::PopsicleList<int>();
+    public scg::IList<int> PackedInt32List {
+      get { return pbc::Lists.AsReadOnly(packedInt32_); }
+    }
+    public int PackedInt32Count {
+      get { return packedInt32_.Count; }
+    }
+    public int GetPackedInt32(int index) {
+      return packedInt32_[index];
+    }
+    
+    private int packedInt64MemoizedSerializedSize;
+    private pbc::PopsicleList<long> packedInt64_ = new pbc::PopsicleList<long>();
+    public scg::IList<long> PackedInt64List {
+      get { return pbc::Lists.AsReadOnly(packedInt64_); }
+    }
+    public int PackedInt64Count {
+      get { return packedInt64_.Count; }
+    }
+    public long GetPackedInt64(int index) {
+      return packedInt64_[index];
+    }
+    
+    private int packedUint32MemoizedSerializedSize;
+    private pbc::PopsicleList<uint> packedUint32_ = new pbc::PopsicleList<uint>();
+    public scg::IList<uint> PackedUint32List {
+      get { return pbc::Lists.AsReadOnly(packedUint32_); }
+    }
+    public int PackedUint32Count {
+      get { return packedUint32_.Count; }
+    }
+    public uint GetPackedUint32(int index) {
+      return packedUint32_[index];
+    }
+    
+    private int packedUint64MemoizedSerializedSize;
+    private pbc::PopsicleList<ulong> packedUint64_ = new pbc::PopsicleList<ulong>();
+    public scg::IList<ulong> PackedUint64List {
+      get { return pbc::Lists.AsReadOnly(packedUint64_); }
+    }
+    public int PackedUint64Count {
+      get { return packedUint64_.Count; }
+    }
+    public ulong GetPackedUint64(int index) {
+      return packedUint64_[index];
+    }
+    
+    private int packedSint32MemoizedSerializedSize;
+    private pbc::PopsicleList<int> packedSint32_ = new pbc::PopsicleList<int>();
+    public scg::IList<int> PackedSint32List {
+      get { return pbc::Lists.AsReadOnly(packedSint32_); }
+    }
+    public int PackedSint32Count {
+      get { return packedSint32_.Count; }
+    }
+    public int GetPackedSint32(int index) {
+      return packedSint32_[index];
+    }
+    
+    private int packedSint64MemoizedSerializedSize;
+    private pbc::PopsicleList<long> packedSint64_ = new pbc::PopsicleList<long>();
+    public scg::IList<long> PackedSint64List {
+      get { return pbc::Lists.AsReadOnly(packedSint64_); }
+    }
+    public int PackedSint64Count {
+      get { return packedSint64_.Count; }
+    }
+    public long GetPackedSint64(int index) {
+      return packedSint64_[index];
+    }
+    
+    private int packedFixed32MemoizedSerializedSize;
+    private pbc::PopsicleList<uint> packedFixed32_ = new pbc::PopsicleList<uint>();
+    public scg::IList<uint> PackedFixed32List {
+      get { return pbc::Lists.AsReadOnly(packedFixed32_); }
+    }
+    public int PackedFixed32Count {
+      get { return packedFixed32_.Count; }
+    }
+    public uint GetPackedFixed32(int index) {
+      return packedFixed32_[index];
+    }
+    
+    private int packedFixed64MemoizedSerializedSize;
+    private pbc::PopsicleList<ulong> packedFixed64_ = new pbc::PopsicleList<ulong>();
+    public scg::IList<ulong> PackedFixed64List {
+      get { return pbc::Lists.AsReadOnly(packedFixed64_); }
+    }
+    public int PackedFixed64Count {
+      get { return packedFixed64_.Count; }
+    }
+    public ulong GetPackedFixed64(int index) {
+      return packedFixed64_[index];
+    }
+    
+    private int packedSfixed32MemoizedSerializedSize;
+    private pbc::PopsicleList<int> packedSfixed32_ = new pbc::PopsicleList<int>();
+    public scg::IList<int> PackedSfixed32List {
+      get { return pbc::Lists.AsReadOnly(packedSfixed32_); }
+    }
+    public int PackedSfixed32Count {
+      get { return packedSfixed32_.Count; }
+    }
+    public int GetPackedSfixed32(int index) {
+      return packedSfixed32_[index];
+    }
+    
+    private int packedSfixed64MemoizedSerializedSize;
+    private pbc::PopsicleList<long> packedSfixed64_ = new pbc::PopsicleList<long>();
+    public scg::IList<long> PackedSfixed64List {
+      get { return pbc::Lists.AsReadOnly(packedSfixed64_); }
+    }
+    public int PackedSfixed64Count {
+      get { return packedSfixed64_.Count; }
+    }
+    public long GetPackedSfixed64(int index) {
+      return packedSfixed64_[index];
+    }
+    
+    private int packedFloatMemoizedSerializedSize;
+    private pbc::PopsicleList<float> packedFloat_ = new pbc::PopsicleList<float>();
+    public scg::IList<float> PackedFloatList {
+      get { return pbc::Lists.AsReadOnly(packedFloat_); }
+    }
+    public int PackedFloatCount {
+      get { return packedFloat_.Count; }
+    }
+    public float GetPackedFloat(int index) {
+      return packedFloat_[index];
+    }
+    
+    private int packedDoubleMemoizedSerializedSize;
+    private pbc::PopsicleList<double> packedDouble_ = new pbc::PopsicleList<double>();
+    public scg::IList<double> PackedDoubleList {
+      get { return pbc::Lists.AsReadOnly(packedDouble_); }
+    }
+    public int PackedDoubleCount {
+      get { return packedDouble_.Count; }
+    }
+    public double GetPackedDouble(int index) {
+      return packedDouble_[index];
+    }
+    
+    private int packedBoolMemoizedSerializedSize;
+    private pbc::PopsicleList<bool> packedBool_ = new pbc::PopsicleList<bool>();
+    public scg::IList<bool> PackedBoolList {
+      get { return pbc::Lists.AsReadOnly(packedBool_); }
+    }
+    public int PackedBoolCount {
+      get { return packedBool_.Count; }
+    }
+    public bool GetPackedBool(int index) {
+      return packedBool_[index];
+    }
+    
+    private int packedEnumMemoizedSerializedSize;
+    private pbc::PopsicleList<global::Google.ProtocolBuffers.TestProtos.ForeignEnum> packedEnum_ = new pbc::PopsicleList<global::Google.ProtocolBuffers.TestProtos.ForeignEnum>();
+    public scg::IList<global::Google.ProtocolBuffers.TestProtos.ForeignEnum> PackedEnumList {
+      get { return pbc::Lists.AsReadOnly(packedEnum_); }
+    }
+    public int PackedEnumCount {
+      get { return packedEnum_.Count; }
+    }
+    public global::Google.ProtocolBuffers.TestProtos.ForeignEnum GetPackedEnum(int index) {
+      return packedEnum_[index];
+    }
+    
+    public override bool IsInitialized {
+      get {
+        return true;
+      }
+    }
+    
+    public override void WriteTo(pb::CodedOutputStream output) {
+      if (packedInt32_.Count > 0) {
+        output.WriteRawVarint32(722);
+        output.WriteRawVarint32((uint) packedInt32MemoizedSerializedSize);
+        foreach (int element in packedInt32_) {
+          output.WriteInt32NoTag(element);
+        }
+      }
+      if (packedInt64_.Count > 0) {
+        output.WriteRawVarint32(730);
+        output.WriteRawVarint32((uint) packedInt64MemoizedSerializedSize);
+        foreach (long element in packedInt64_) {
+          output.WriteInt64NoTag(element);
+        }
+      }
+      if (packedUint32_.Count > 0) {
+        output.WriteRawVarint32(738);
+        output.WriteRawVarint32((uint) packedUint32MemoizedSerializedSize);
+        foreach (uint element in packedUint32_) {
+          output.WriteUInt32NoTag(element);
+        }
+      }
+      if (packedUint64_.Count > 0) {
+        output.WriteRawVarint32(746);
+        output.WriteRawVarint32((uint) packedUint64MemoizedSerializedSize);
+        foreach (ulong element in packedUint64_) {
+          output.WriteUInt64NoTag(element);
+        }
+      }
+      if (packedSint32_.Count > 0) {
+        output.WriteRawVarint32(754);
+        output.WriteRawVarint32((uint) packedSint32MemoizedSerializedSize);
+        foreach (int element in packedSint32_) {
+          output.WriteSInt32NoTag(element);
+        }
+      }
+      if (packedSint64_.Count > 0) {
+        output.WriteRawVarint32(762);
+        output.WriteRawVarint32((uint) packedSint64MemoizedSerializedSize);
+        foreach (long element in packedSint64_) {
+          output.WriteSInt64NoTag(element);
+        }
+      }
+      if (packedFixed32_.Count > 0) {
+        output.WriteRawVarint32(770);
+        output.WriteRawVarint32((uint) packedFixed32MemoizedSerializedSize);
+        foreach (uint element in packedFixed32_) {
+          output.WriteFixed32NoTag(element);
+        }
+      }
+      if (packedFixed64_.Count > 0) {
+        output.WriteRawVarint32(778);
+        output.WriteRawVarint32((uint) packedFixed64MemoizedSerializedSize);
+        foreach (ulong element in packedFixed64_) {
+          output.WriteFixed64NoTag(element);
+        }
+      }
+      if (packedSfixed32_.Count > 0) {
+        output.WriteRawVarint32(786);
+        output.WriteRawVarint32((uint) packedSfixed32MemoizedSerializedSize);
+        foreach (int element in packedSfixed32_) {
+          output.WriteSFixed32NoTag(element);
+        }
+      }
+      if (packedSfixed64_.Count > 0) {
+        output.WriteRawVarint32(794);
+        output.WriteRawVarint32((uint) packedSfixed64MemoizedSerializedSize);
+        foreach (long element in packedSfixed64_) {
+          output.WriteSFixed64NoTag(element);
+        }
+      }
+      if (packedFloat_.Count > 0) {
+        output.WriteRawVarint32(802);
+        output.WriteRawVarint32((uint) packedFloatMemoizedSerializedSize);
+        foreach (float element in packedFloat_) {
+          output.WriteFloatNoTag(element);
+        }
+      }
+      if (packedDouble_.Count > 0) {
+        output.WriteRawVarint32(810);
+        output.WriteRawVarint32((uint) packedDoubleMemoizedSerializedSize);
+        foreach (double element in packedDouble_) {
+          output.WriteDoubleNoTag(element);
+        }
+      }
+      if (packedBool_.Count > 0) {
+        output.WriteRawVarint32(818);
+        output.WriteRawVarint32((uint) packedBoolMemoizedSerializedSize);
+        foreach (bool element in packedBool_) {
+          output.WriteBoolNoTag(element);
+        }
+      }
+      if (packedEnum_.Count > 0) {
+        output.WriteRawVarint32(826);
+        output.WriteRawVarint32((uint) packedEnumMemoizedSerializedSize);
+        foreach (int element in packedEnum_) {
+          output.WriteEnumNoTag(element);
+        }
+      }
+      UnknownFields.WriteTo(output);
+    }
+    
+    private int memoizedSerializedSize = -1;
+    public override int SerializedSize {
+      get {
+        int size = memoizedSerializedSize;
+        if (size != -1) return size;
+        
+        size = 0;
+        {
+          int dataSize = 0;
+          foreach (int element in PackedInt32List) {
+            dataSize += pb::CodedOutputStream.ComputeInt32SizeNoTag(element);
+          }
+          size += dataSize;
+          size += 2;
+          size += pb::CodedOutputStream.ComputeInt32SizeNoTag(dataSize);
+          packedInt32MemoizedSerializedSize = dataSize;
+        }
+        {
+          int dataSize = 0;
+          foreach (long element in PackedInt64List) {
+            dataSize += pb::CodedOutputStream.ComputeInt64SizeNoTag(element);
+          }
+          size += dataSize;
+          size += 2;
+          size += pb::CodedOutputStream.ComputeInt32SizeNoTag(dataSize);
+          packedInt64MemoizedSerializedSize = dataSize;
+        }
+        {
+          int dataSize = 0;
+          foreach (uint element in PackedUint32List) {
+            dataSize += pb::CodedOutputStream.ComputeUInt32SizeNoTag(element);
+          }
+          size += dataSize;
+          size += 2;
+          size += pb::CodedOutputStream.ComputeInt32SizeNoTag(dataSize);
+          packedUint32MemoizedSerializedSize = dataSize;
+        }
+        {
+          int dataSize = 0;
+          foreach (ulong element in PackedUint64List) {
+            dataSize += pb::CodedOutputStream.ComputeUInt64SizeNoTag(element);
+          }
+          size += dataSize;
+          size += 2;
+          size += pb::CodedOutputStream.ComputeInt32SizeNoTag(dataSize);
+          packedUint64MemoizedSerializedSize = dataSize;
+        }
+        {
+          int dataSize = 0;
+          foreach (int element in PackedSint32List) {
+            dataSize += pb::CodedOutputStream.ComputeSInt32SizeNoTag(element);
+          }
+          size += dataSize;
+          size += 2;
+          size += pb::CodedOutputStream.ComputeInt32SizeNoTag(dataSize);
+          packedSint32MemoizedSerializedSize = dataSize;
+        }
+        {
+          int dataSize = 0;
+          foreach (long element in PackedSint64List) {
+            dataSize += pb::CodedOutputStream.ComputeSInt64SizeNoTag(element);
+          }
+          size += dataSize;
+          size += 2;
+          size += pb::CodedOutputStream.ComputeInt32SizeNoTag(dataSize);
+          packedSint64MemoizedSerializedSize = dataSize;
+        }
+        {
+          int dataSize = 0;
+          dataSize = 4 * packedFixed32_.Count;
+          size += dataSize;
+          size += 2;
+          size += pb::CodedOutputStream.ComputeInt32SizeNoTag(dataSize);
+          packedFixed32MemoizedSerializedSize = dataSize;
+        }
+        {
+          int dataSize = 0;
+          dataSize = 8 * packedFixed64_.Count;
+          size += dataSize;
+          size += 2;
+          size += pb::CodedOutputStream.ComputeInt32SizeNoTag(dataSize);
+          packedFixed64MemoizedSerializedSize = dataSize;
+        }
+        {
+          int dataSize = 0;
+          dataSize = 4 * packedSfixed32_.Count;
+          size += dataSize;
+          size += 2;
+          size += pb::CodedOutputStream.ComputeInt32SizeNoTag(dataSize);
+          packedSfixed32MemoizedSerializedSize = dataSize;
+        }
+        {
+          int dataSize = 0;
+          dataSize = 8 * packedSfixed64_.Count;
+          size += dataSize;
+          size += 2;
+          size += pb::CodedOutputStream.ComputeInt32SizeNoTag(dataSize);
+          packedSfixed64MemoizedSerializedSize = dataSize;
+        }
+        {
+          int dataSize = 0;
+          dataSize = 4 * packedFloat_.Count;
+          size += dataSize;
+          size += 2;
+          size += pb::CodedOutputStream.ComputeInt32SizeNoTag(dataSize);
+          packedFloatMemoizedSerializedSize = dataSize;
+        }
+        {
+          int dataSize = 0;
+          dataSize = 8 * packedDouble_.Count;
+          size += dataSize;
+          size += 2;
+          size += pb::CodedOutputStream.ComputeInt32SizeNoTag(dataSize);
+          packedDoubleMemoizedSerializedSize = dataSize;
+        }
+        {
+          int dataSize = 0;
+          dataSize = 1 * packedBool_.Count;
+          size += dataSize;
+          size += 2;
+          size += pb::CodedOutputStream.ComputeInt32SizeNoTag(dataSize);
+          packedBoolMemoizedSerializedSize = dataSize;
+        }
+        {
+          int dataSize = 0;
+          if (packedEnum_.Count > 0) {
+            foreach (global::Google.ProtocolBuffers.TestProtos.ForeignEnum element in packedEnum_) {
+              dataSize += pb::CodedOutputStream.ComputeEnumSizeNoTag((int) element);
+            }
+            size += dataSize;
+            size += 2;
+            size += pb::CodedOutputStream.ComputeRawVarint32Size((uint) dataSize);
+          }
+          packedEnumMemoizedSerializedSize = dataSize;
+        }
+        size += UnknownFields.SerializedSize;
+        memoizedSerializedSize = size;
+        return size;
+      }
+    }
+    
+    public static TestPackedTypes ParseFrom(pb::ByteString data) {
+      return ((Builder) CreateBuilder().MergeFrom(data)).BuildParsed();
+    }
+    public static TestPackedTypes ParseFrom(pb::ByteString data, pb::ExtensionRegistry extensionRegistry) {
+      return ((Builder) CreateBuilder().MergeFrom(data, extensionRegistry)).BuildParsed();
+    }
+    public static TestPackedTypes ParseFrom(byte[] data) {
+      return ((Builder) CreateBuilder().MergeFrom(data)).BuildParsed();
+    }
+    public static TestPackedTypes ParseFrom(byte[] data, pb::ExtensionRegistry extensionRegistry) {
+      return ((Builder) CreateBuilder().MergeFrom(data, extensionRegistry)).BuildParsed();
+    }
+    public static TestPackedTypes ParseFrom(global::System.IO.Stream input) {
+      return ((Builder) CreateBuilder().MergeFrom(input)).BuildParsed();
+    }
+    public static TestPackedTypes ParseFrom(global::System.IO.Stream input, pb::ExtensionRegistry extensionRegistry) {
+      return ((Builder) CreateBuilder().MergeFrom(input, extensionRegistry)).BuildParsed();
+    }
+    public static TestPackedTypes ParseFrom(pb::CodedInputStream input) {
+      return ((Builder) CreateBuilder().MergeFrom(input)).BuildParsed();
+    }
+    public static TestPackedTypes ParseFrom(pb::CodedInputStream input, pb::ExtensionRegistry extensionRegistry) {
+      return ((Builder) CreateBuilder().MergeFrom(input, extensionRegistry)).BuildParsed();
+    }
+    public static Builder CreateBuilder() { return new Builder(); }
+    public override Builder CreateBuilderForType() { return new Builder(); }
+    public static Builder CreateBuilder(TestPackedTypes prototype) {
+      return (Builder) new Builder().MergeFrom(prototype);
+    }
+    
+    public sealed partial class Builder : pb::GeneratedBuilder<TestPackedTypes, Builder> {
+      protected override Builder ThisBuilder {
+        get { return this; }
+      }
+      public Builder() {}
+      
+      TestPackedTypes result = new TestPackedTypes();
+      
+      protected override TestPackedTypes MessageBeingBuilt {
+        get { return result; }
+      }
+      
+      public override Builder Clear() {
+        result = new TestPackedTypes();
+        return this;
+      }
+      
+      public override Builder Clone() {
+        return new Builder().MergeFrom(result);
+      }
+      
+      public override pbd::MessageDescriptor DescriptorForType {
+        get { return TestPackedTypes.Descriptor; }
+      }
+      
+      public override TestPackedTypes DefaultInstanceForType {
+        get { return TestPackedTypes.DefaultInstance; }
+      }
+      
+      public override TestPackedTypes BuildPartial() {
+        result.packedInt32_.MakeReadOnly();
+        result.packedInt64_.MakeReadOnly();
+        result.packedUint32_.MakeReadOnly();
+        result.packedUint64_.MakeReadOnly();
+        result.packedSint32_.MakeReadOnly();
+        result.packedSint64_.MakeReadOnly();
+        result.packedFixed32_.MakeReadOnly();
+        result.packedFixed64_.MakeReadOnly();
+        result.packedSfixed32_.MakeReadOnly();
+        result.packedSfixed64_.MakeReadOnly();
+        result.packedFloat_.MakeReadOnly();
+        result.packedDouble_.MakeReadOnly();
+        result.packedBool_.MakeReadOnly();
+        result.packedEnum_.MakeReadOnly();
+        TestPackedTypes returnMe = result;
+        result = null;
+        return returnMe;
+      }
+      
+      public override Builder MergeFrom(pb::IMessage other) {
+        if (other is TestPackedTypes) {
+          return MergeFrom((TestPackedTypes) other);
+        } else {
+          base.MergeFrom(other);
+          return this;
+        }
+      }
+      
+      public override Builder MergeFrom(TestPackedTypes other) {
+        if (other == TestPackedTypes.DefaultInstance) return this;
+        if (other.packedInt32_.Count != 0) {
+          base.AddRange(other.packedInt32_, result.packedInt32_);
+        }
+        if (other.packedInt64_.Count != 0) {
+          base.AddRange(other.packedInt64_, result.packedInt64_);
+        }
+        if (other.packedUint32_.Count != 0) {
+          base.AddRange(other.packedUint32_, result.packedUint32_);
+        }
+        if (other.packedUint64_.Count != 0) {
+          base.AddRange(other.packedUint64_, result.packedUint64_);
+        }
+        if (other.packedSint32_.Count != 0) {
+          base.AddRange(other.packedSint32_, result.packedSint32_);
+        }
+        if (other.packedSint64_.Count != 0) {
+          base.AddRange(other.packedSint64_, result.packedSint64_);
+        }
+        if (other.packedFixed32_.Count != 0) {
+          base.AddRange(other.packedFixed32_, result.packedFixed32_);
+        }
+        if (other.packedFixed64_.Count != 0) {
+          base.AddRange(other.packedFixed64_, result.packedFixed64_);
+        }
+        if (other.packedSfixed32_.Count != 0) {
+          base.AddRange(other.packedSfixed32_, result.packedSfixed32_);
+        }
+        if (other.packedSfixed64_.Count != 0) {
+          base.AddRange(other.packedSfixed64_, result.packedSfixed64_);
+        }
+        if (other.packedFloat_.Count != 0) {
+          base.AddRange(other.packedFloat_, result.packedFloat_);
+        }
+        if (other.packedDouble_.Count != 0) {
+          base.AddRange(other.packedDouble_, result.packedDouble_);
+        }
+        if (other.packedBool_.Count != 0) {
+          base.AddRange(other.packedBool_, result.packedBool_);
+        }
+        if (other.packedEnum_.Count != 0) {
+          base.AddRange(other.packedEnum_, result.packedEnum_);
+        }
+        this.MergeUnknownFields(other.UnknownFields);
+        return this;
+      }
+      
+      public override Builder MergeFrom(pb::CodedInputStream input) {
+        return MergeFrom(input, pb::ExtensionRegistry.Empty);
+      }
+      
+      public override Builder MergeFrom(pb::CodedInputStream input, pb::ExtensionRegistry extensionRegistry) {
+        pb::UnknownFieldSet.Builder unknownFields = pb::UnknownFieldSet.CreateBuilder(this.UnknownFields);
+        while (true) {
+          uint tag = input.ReadTag();
+          switch (tag) {
+            case 0: {
+              this.UnknownFields = unknownFields.Build();
+              return this;
+            }
+            default: {
+              if (!ParseUnknownField(input, unknownFields, extensionRegistry, tag)) {
+                this.UnknownFields = unknownFields.Build();
+                return this;
+              }
+              break;
+            }
+            case 722: {
+              int length = input.ReadInt32();
+              int limit = input.PushLimit(length);
+              while (!input.ReachedLimit) {
+                AddPackedInt32(input.ReadInt32());
+              }
+              input.PopLimit(limit);
+              break;
+            }
+            case 730: {
+              int length = input.ReadInt32();
+              int limit = input.PushLimit(length);
+              while (!input.ReachedLimit) {
+                AddPackedInt64(input.ReadInt64());
+              }
+              input.PopLimit(limit);
+              break;
+            }
+            case 738: {
+              int length = input.ReadInt32();
+              int limit = input.PushLimit(length);
+              while (!input.ReachedLimit) {
+                AddPackedUint32(input.ReadUInt32());
+              }
+              input.PopLimit(limit);
+              break;
+            }
+            case 746: {
+              int length = input.ReadInt32();
+              int limit = input.PushLimit(length);
+              while (!input.ReachedLimit) {
+                AddPackedUint64(input.ReadUInt64());
+              }
+              input.PopLimit(limit);
+              break;
+            }
+            case 754: {
+              int length = input.ReadInt32();
+              int limit = input.PushLimit(length);
+              while (!input.ReachedLimit) {
+                AddPackedSint32(input.ReadSInt32());
+              }
+              input.PopLimit(limit);
+              break;
+            }
+            case 762: {
+              int length = input.ReadInt32();
+              int limit = input.PushLimit(length);
+              while (!input.ReachedLimit) {
+                AddPackedSint64(input.ReadSInt64());
+              }
+              input.PopLimit(limit);
+              break;
+            }
+            case 770: {
+              int length = input.ReadInt32();
+              int limit = input.PushLimit(length);
+              while (!input.ReachedLimit) {
+                AddPackedFixed32(input.ReadFixed32());
+              }
+              input.PopLimit(limit);
+              break;
+            }
+            case 778: {
+              int length = input.ReadInt32();
+              int limit = input.PushLimit(length);
+              while (!input.ReachedLimit) {
+                AddPackedFixed64(input.ReadFixed64());
+              }
+              input.PopLimit(limit);
+              break;
+            }
+            case 786: {
+              int length = input.ReadInt32();
+              int limit = input.PushLimit(length);
+              while (!input.ReachedLimit) {
+                AddPackedSfixed32(input.ReadSFixed32());
+              }
+              input.PopLimit(limit);
+              break;
+            }
+            case 794: {
+              int length = input.ReadInt32();
+              int limit = input.PushLimit(length);
+              while (!input.ReachedLimit) {
+                AddPackedSfixed64(input.ReadSFixed64());
+              }
+              input.PopLimit(limit);
+              break;
+            }
+            case 802: {
+              int length = input.ReadInt32();
+              int limit = input.PushLimit(length);
+              while (!input.ReachedLimit) {
+                AddPackedFloat(input.ReadFloat());
+              }
+              input.PopLimit(limit);
+              break;
+            }
+            case 810: {
+              int length = input.ReadInt32();
+              int limit = input.PushLimit(length);
+              while (!input.ReachedLimit) {
+                AddPackedDouble(input.ReadDouble());
+              }
+              input.PopLimit(limit);
+              break;
+            }
+            case 818: {
+              int length = input.ReadInt32();
+              int limit = input.PushLimit(length);
+              while (!input.ReachedLimit) {
+                AddPackedBool(input.ReadBool());
+              }
+              input.PopLimit(limit);
+              break;
+            }
+            case 826: {
+              int length = input.ReadInt32();
+              int oldLimit = input.PushLimit(length);
+              while (!input.ReachedLimit) {
+                int rawValue = input.ReadEnum();
+                if (!global::System.Enum.IsDefined(typeof(global::Google.ProtocolBuffers.TestProtos.ForeignEnum), rawValue)) {
+                  unknownFields.MergeVarintField(103, (ulong) rawValue);
+                } else {
+                  AddPackedEnum((global::Google.ProtocolBuffers.TestProtos.ForeignEnum) rawValue);
+                }
+              }
+              input.PopLimit(oldLimit);
+              break;
+            }
+          }
+        }
+      }
+      
+      
+      public scg::IList<int> PackedInt32List {
+        get { return result.packedInt32_; }
+      }
+      public int PackedInt32Count {
+        get { return result.PackedInt32Count; }
+      }
+      public int GetPackedInt32(int index) {
+        return result.GetPackedInt32(index);
+      }
+      public Builder SetPackedInt32(int index, int value) {
+        result.packedInt32_[index] = value;
+        return this;
+      }
+      public Builder AddPackedInt32(int value) {
+        result.packedInt32_.Add(value);
+        return this;
+      }
+      public Builder AddRangePackedInt32(scg::IEnumerable<int> values) {
+        base.AddRange(values, result.packedInt32_);
+        return this;
+      }
+      public Builder ClearPackedInt32() {
+        result.packedInt32_.Clear();
+        return this;
+      }
+      
+      public scg::IList<long> PackedInt64List {
+        get { return result.packedInt64_; }
+      }
+      public int PackedInt64Count {
+        get { return result.PackedInt64Count; }
+      }
+      public long GetPackedInt64(int index) {
+        return result.GetPackedInt64(index);
+      }
+      public Builder SetPackedInt64(int index, long value) {
+        result.packedInt64_[index] = value;
+        return this;
+      }
+      public Builder AddPackedInt64(long value) {
+        result.packedInt64_.Add(value);
+        return this;
+      }
+      public Builder AddRangePackedInt64(scg::IEnumerable<long> values) {
+        base.AddRange(values, result.packedInt64_);
+        return this;
+      }
+      public Builder ClearPackedInt64() {
+        result.packedInt64_.Clear();
+        return this;
+      }
+      
+      public scg::IList<uint> PackedUint32List {
+        get { return result.packedUint32_; }
+      }
+      public int PackedUint32Count {
+        get { return result.PackedUint32Count; }
+      }
+      public uint GetPackedUint32(int index) {
+        return result.GetPackedUint32(index);
+      }
+      public Builder SetPackedUint32(int index, uint value) {
+        result.packedUint32_[index] = value;
+        return this;
+      }
+      public Builder AddPackedUint32(uint value) {
+        result.packedUint32_.Add(value);
+        return this;
+      }
+      public Builder AddRangePackedUint32(scg::IEnumerable<uint> values) {
+        base.AddRange(values, result.packedUint32_);
+        return this;
+      }
+      public Builder ClearPackedUint32() {
+        result.packedUint32_.Clear();
+        return this;
+      }
+      
+      public scg::IList<ulong> PackedUint64List {
+        get { return result.packedUint64_; }
+      }
+      public int PackedUint64Count {
+        get { return result.PackedUint64Count; }
+      }
+      public ulong GetPackedUint64(int index) {
+        return result.GetPackedUint64(index);
+      }
+      public Builder SetPackedUint64(int index, ulong value) {
+        result.packedUint64_[index] = value;
+        return this;
+      }
+      public Builder AddPackedUint64(ulong value) {
+        result.packedUint64_.Add(value);
+        return this;
+      }
+      public Builder AddRangePackedUint64(scg::IEnumerable<ulong> values) {
+        base.AddRange(values, result.packedUint64_);
+        return this;
+      }
+      public Builder ClearPackedUint64() {
+        result.packedUint64_.Clear();
+        return this;
+      }
+      
+      public scg::IList<int> PackedSint32List {
+        get { return result.packedSint32_; }
+      }
+      public int PackedSint32Count {
+        get { return result.PackedSint32Count; }
+      }
+      public int GetPackedSint32(int index) {
+        return result.GetPackedSint32(index);
+      }
+      public Builder SetPackedSint32(int index, int value) {
+        result.packedSint32_[index] = value;
+        return this;
+      }
+      public Builder AddPackedSint32(int value) {
+        result.packedSint32_.Add(value);
+        return this;
+      }
+      public Builder AddRangePackedSint32(scg::IEnumerable<int> values) {
+        base.AddRange(values, result.packedSint32_);
+        return this;
+      }
+      public Builder ClearPackedSint32() {
+        result.packedSint32_.Clear();
+        return this;
+      }
+      
+      public scg::IList<long> PackedSint64List {
+        get { return result.packedSint64_; }
+      }
+      public int PackedSint64Count {
+        get { return result.PackedSint64Count; }
+      }
+      public long GetPackedSint64(int index) {
+        return result.GetPackedSint64(index);
+      }
+      public Builder SetPackedSint64(int index, long value) {
+        result.packedSint64_[index] = value;
+        return this;
+      }
+      public Builder AddPackedSint64(long value) {
+        result.packedSint64_.Add(value);
+        return this;
+      }
+      public Builder AddRangePackedSint64(scg::IEnumerable<long> values) {
+        base.AddRange(values, result.packedSint64_);
+        return this;
+      }
+      public Builder ClearPackedSint64() {
+        result.packedSint64_.Clear();
+        return this;
+      }
+      
+      public scg::IList<uint> PackedFixed32List {
+        get { return result.packedFixed32_; }
+      }
+      public int PackedFixed32Count {
+        get { return result.PackedFixed32Count; }
+      }
+      public uint GetPackedFixed32(int index) {
+        return result.GetPackedFixed32(index);
+      }
+      public Builder SetPackedFixed32(int index, uint value) {
+        result.packedFixed32_[index] = value;
+        return this;
+      }
+      public Builder AddPackedFixed32(uint value) {
+        result.packedFixed32_.Add(value);
+        return this;
+      }
+      public Builder AddRangePackedFixed32(scg::IEnumerable<uint> values) {
+        base.AddRange(values, result.packedFixed32_);
+        return this;
+      }
+      public Builder ClearPackedFixed32() {
+        result.packedFixed32_.Clear();
+        return this;
+      }
+      
+      public scg::IList<ulong> PackedFixed64List {
+        get { return result.packedFixed64_; }
+      }
+      public int PackedFixed64Count {
+        get { return result.PackedFixed64Count; }
+      }
+      public ulong GetPackedFixed64(int index) {
+        return result.GetPackedFixed64(index);
+      }
+      public Builder SetPackedFixed64(int index, ulong value) {
+        result.packedFixed64_[index] = value;
+        return this;
+      }
+      public Builder AddPackedFixed64(ulong value) {
+        result.packedFixed64_.Add(value);
+        return this;
+      }
+      public Builder AddRangePackedFixed64(scg::IEnumerable<ulong> values) {
+        base.AddRange(values, result.packedFixed64_);
+        return this;
+      }
+      public Builder ClearPackedFixed64() {
+        result.packedFixed64_.Clear();
+        return this;
+      }
+      
+      public scg::IList<int> PackedSfixed32List {
+        get { return result.packedSfixed32_; }
+      }
+      public int PackedSfixed32Count {
+        get { return result.PackedSfixed32Count; }
+      }
+      public int GetPackedSfixed32(int index) {
+        return result.GetPackedSfixed32(index);
+      }
+      public Builder SetPackedSfixed32(int index, int value) {
+        result.packedSfixed32_[index] = value;
+        return this;
+      }
+      public Builder AddPackedSfixed32(int value) {
+        result.packedSfixed32_.Add(value);
+        return this;
+      }
+      public Builder AddRangePackedSfixed32(scg::IEnumerable<int> values) {
+        base.AddRange(values, result.packedSfixed32_);
+        return this;
+      }
+      public Builder ClearPackedSfixed32() {
+        result.packedSfixed32_.Clear();
+        return this;
+      }
+      
+      public scg::IList<long> PackedSfixed64List {
+        get { return result.packedSfixed64_; }
+      }
+      public int PackedSfixed64Count {
+        get { return result.PackedSfixed64Count; }
+      }
+      public long GetPackedSfixed64(int index) {
+        return result.GetPackedSfixed64(index);
+      }
+      public Builder SetPackedSfixed64(int index, long value) {
+        result.packedSfixed64_[index] = value;
+        return this;
+      }
+      public Builder AddPackedSfixed64(long value) {
+        result.packedSfixed64_.Add(value);
+        return this;
+      }
+      public Builder AddRangePackedSfixed64(scg::IEnumerable<long> values) {
+        base.AddRange(values, result.packedSfixed64_);
+        return this;
+      }
+      public Builder ClearPackedSfixed64() {
+        result.packedSfixed64_.Clear();
+        return this;
+      }
+      
+      public scg::IList<float> PackedFloatList {
+        get { return result.packedFloat_; }
+      }
+      public int PackedFloatCount {
+        get { return result.PackedFloatCount; }
+      }
+      public float GetPackedFloat(int index) {
+        return result.GetPackedFloat(index);
+      }
+      public Builder SetPackedFloat(int index, float value) {
+        result.packedFloat_[index] = value;
+        return this;
+      }
+      public Builder AddPackedFloat(float value) {
+        result.packedFloat_.Add(value);
+        return this;
+      }
+      public Builder AddRangePackedFloat(scg::IEnumerable<float> values) {
+        base.AddRange(values, result.packedFloat_);
+        return this;
+      }
+      public Builder ClearPackedFloat() {
+        result.packedFloat_.Clear();
+        return this;
+      }
+      
+      public scg::IList<double> PackedDoubleList {
+        get { return result.packedDouble_; }
+      }
+      public int PackedDoubleCount {
+        get { return result.PackedDoubleCount; }
+      }
+      public double GetPackedDouble(int index) {
+        return result.GetPackedDouble(index);
+      }
+      public Builder SetPackedDouble(int index, double value) {
+        result.packedDouble_[index] = value;
+        return this;
+      }
+      public Builder AddPackedDouble(double value) {
+        result.packedDouble_.Add(value);
+        return this;
+      }
+      public Builder AddRangePackedDouble(scg::IEnumerable<double> values) {
+        base.AddRange(values, result.packedDouble_);
+        return this;
+      }
+      public Builder ClearPackedDouble() {
+        result.packedDouble_.Clear();
+        return this;
+      }
+      
+      public scg::IList<bool> PackedBoolList {
+        get { return result.packedBool_; }
+      }
+      public int PackedBoolCount {
+        get { return result.PackedBoolCount; }
+      }
+      public bool GetPackedBool(int index) {
+        return result.GetPackedBool(index);
+      }
+      public Builder SetPackedBool(int index, bool value) {
+        result.packedBool_[index] = value;
+        return this;
+      }
+      public Builder AddPackedBool(bool value) {
+        result.packedBool_.Add(value);
+        return this;
+      }
+      public Builder AddRangePackedBool(scg::IEnumerable<bool> values) {
+        base.AddRange(values, result.packedBool_);
+        return this;
+      }
+      public Builder ClearPackedBool() {
+        result.packedBool_.Clear();
+        return this;
+      }
+      
+      public scg::IList<global::Google.ProtocolBuffers.TestProtos.ForeignEnum> PackedEnumList {
+        get { return result.packedEnum_; }
+      }
+      public int PackedEnumCount {
+        get { return result.PackedEnumCount; }
+      }
+      public global::Google.ProtocolBuffers.TestProtos.ForeignEnum GetPackedEnum(int index) {
+        return result.GetPackedEnum(index);
+      }
+      public Builder SetPackedEnum(int index, global::Google.ProtocolBuffers.TestProtos.ForeignEnum value) {
+        result.packedEnum_[index] = value;
+        return this;
+      }
+      public Builder AddPackedEnum(global::Google.ProtocolBuffers.TestProtos.ForeignEnum value) {
+        result.packedEnum_.Add(value);
+        return this;
+      }
+      public Builder AddRangePackedEnum(scg::IEnumerable<global::Google.ProtocolBuffers.TestProtos.ForeignEnum> values) {
+        base.AddRange(values, result.packedEnum_);
+        return this;
+      }
+      public Builder ClearPackedEnum() {
+        result.packedEnum_.Clear();
+        return this;
+      }
+    }
+  }
+  
+  public sealed partial class TestPackedExtensions : pb::ExtendableMessage<TestPackedExtensions, TestPackedExtensions.Builder> {
+    private static readonly TestPackedExtensions defaultInstance = new Builder().BuildPartial();
+    public static TestPackedExtensions DefaultInstance {
+      get { return defaultInstance; }
+    }
+    
+    public override TestPackedExtensions DefaultInstanceForType {
+      get { return defaultInstance; }
+    }
+    
+    protected override TestPackedExtensions ThisMessage {
+      get { return this; }
+    }
+    
+    public static pbd::MessageDescriptor Descriptor {
+      get { return global::Google.ProtocolBuffers.TestProtos.UnitTestProtoFile.internal__static_protobuf_unittest_TestPackedExtensions__Descriptor; }
+    }
+    
+    protected override pb::FieldAccess.FieldAccessorTable<TestPackedExtensions, TestPackedExtensions.Builder> InternalFieldAccessors {
+      get { return global::Google.ProtocolBuffers.TestProtos.UnitTestProtoFile.internal__static_protobuf_unittest_TestPackedExtensions__FieldAccessorTable; }
+    }
+    
+    public override bool IsInitialized {
+      get {
+        if (!ExtensionsAreInitialized) return false;
+        return true;
+      }
+    }
+    
+    public override void WriteTo(pb::CodedOutputStream output) {
+      pb::ExtendableMessage<TestPackedExtensions, TestPackedExtensions.Builder>.ExtensionWriter extensionWriter = CreateExtensionWriter(this);
+      extensionWriter.WriteUntil(536870912, output);
+      UnknownFields.WriteTo(output);
+    }
+    
+    private int memoizedSerializedSize = -1;
+    public override int SerializedSize {
+      get {
+        int size = memoizedSerializedSize;
+        if (size != -1) return size;
+        
+        size = 0;
+        size += ExtensionsSerializedSize;
+        size += UnknownFields.SerializedSize;
+        memoizedSerializedSize = size;
+        return size;
+      }
+    }
+    
+    public static TestPackedExtensions ParseFrom(pb::ByteString data) {
+      return ((Builder) CreateBuilder().MergeFrom(data)).BuildParsed();
+    }
+    public static TestPackedExtensions ParseFrom(pb::ByteString data, pb::ExtensionRegistry extensionRegistry) {
+      return ((Builder) CreateBuilder().MergeFrom(data, extensionRegistry)).BuildParsed();
+    }
+    public static TestPackedExtensions ParseFrom(byte[] data) {
+      return ((Builder) CreateBuilder().MergeFrom(data)).BuildParsed();
+    }
+    public static TestPackedExtensions ParseFrom(byte[] data, pb::ExtensionRegistry extensionRegistry) {
+      return ((Builder) CreateBuilder().MergeFrom(data, extensionRegistry)).BuildParsed();
+    }
+    public static TestPackedExtensions ParseFrom(global::System.IO.Stream input) {
+      return ((Builder) CreateBuilder().MergeFrom(input)).BuildParsed();
+    }
+    public static TestPackedExtensions ParseFrom(global::System.IO.Stream input, pb::ExtensionRegistry extensionRegistry) {
+      return ((Builder) CreateBuilder().MergeFrom(input, extensionRegistry)).BuildParsed();
+    }
+    public static TestPackedExtensions ParseFrom(pb::CodedInputStream input) {
+      return ((Builder) CreateBuilder().MergeFrom(input)).BuildParsed();
+    }
+    public static TestPackedExtensions ParseFrom(pb::CodedInputStream input, pb::ExtensionRegistry extensionRegistry) {
+      return ((Builder) CreateBuilder().MergeFrom(input, extensionRegistry)).BuildParsed();
+    }
+    public static Builder CreateBuilder() { return new Builder(); }
+    public override Builder CreateBuilderForType() { return new Builder(); }
+    public static Builder CreateBuilder(TestPackedExtensions prototype) {
+      return (Builder) new Builder().MergeFrom(prototype);
+    }
+    
+    public sealed partial class Builder : pb::ExtendableBuilder<TestPackedExtensions, Builder> {
+      protected override Builder ThisBuilder {
+        get { return this; }
+      }
+      public Builder() {}
+      
+      TestPackedExtensions result = new TestPackedExtensions();
+      
+      protected override TestPackedExtensions MessageBeingBuilt {
+        get { return result; }
+      }
+      
+      public override Builder Clear() {
+        result = new TestPackedExtensions();
+        return this;
+      }
+      
+      public override Builder Clone() {
+        return new Builder().MergeFrom(result);
+      }
+      
+      public override pbd::MessageDescriptor DescriptorForType {
+        get { return TestPackedExtensions.Descriptor; }
+      }
+      
+      public override TestPackedExtensions DefaultInstanceForType {
+        get { return TestPackedExtensions.DefaultInstance; }
+      }
+      
+      public override TestPackedExtensions BuildPartial() {
+        TestPackedExtensions returnMe = result;
+        result = null;
+        return returnMe;
+      }
+      
+      public override Builder MergeFrom(pb::IMessage other) {
+        if (other is TestPackedExtensions) {
+          return MergeFrom((TestPackedExtensions) other);
+        } else {
+          base.MergeFrom(other);
+          return this;
+        }
+      }
+      
+      public override Builder MergeFrom(TestPackedExtensions other) {
+        if (other == TestPackedExtensions.DefaultInstance) return this;
+          this.MergeExtensionFields(other);
+        this.MergeUnknownFields(other.UnknownFields);
+        return this;
+      }
+      
+      public override Builder MergeFrom(pb::CodedInputStream input) {
+        return MergeFrom(input, pb::ExtensionRegistry.Empty);
+      }
+      
+      public override Builder MergeFrom(pb::CodedInputStream input, pb::ExtensionRegistry extensionRegistry) {
+        pb::UnknownFieldSet.Builder unknownFields = pb::UnknownFieldSet.CreateBuilder(this.UnknownFields);
+        while (true) {
+          uint tag = input.ReadTag();
+          switch (tag) {
+            case 0: {
+              this.UnknownFields = unknownFields.Build();
+              return this;
+            }
+            default: {
+              if (!ParseUnknownField(input, unknownFields, extensionRegistry, tag)) {
+                this.UnknownFields = unknownFields.Build();
+                return this;
+              }
+              break;
+            }
+          }
+        }
+      }
+      
+    }
+  }
+  
   public sealed partial class FooRequest : pb::GeneratedMessage<FooRequest, FooRequest.Builder> {
     private static readonly FooRequest defaultInstance = new Builder().BuildPartial();
     public static FooRequest DefaultInstance {

+ 205 - 0
src/ProtocolBuffers.Test/TestUtil.cs

@@ -158,6 +158,21 @@ namespace Google.ProtocolBuffers {
       registry.Add(UnitTestProtoFile.DefaultImportEnumExtension);
       registry.Add(UnitTestProtoFile.DefaultStringPieceExtension);
       registry.Add(UnitTestProtoFile.DefaultCordExtension);
+
+      registry.Add(UnitTestProtoFile.PackedInt32Extension);
+      registry.Add(UnitTestProtoFile.PackedInt64Extension);
+      registry.Add(UnitTestProtoFile.PackedUint32Extension);
+      registry.Add(UnitTestProtoFile.PackedUint64Extension);
+      registry.Add(UnitTestProtoFile.PackedSint32Extension);
+      registry.Add(UnitTestProtoFile.PackedSint64Extension);
+      registry.Add(UnitTestProtoFile.PackedFixed32Extension);
+      registry.Add(UnitTestProtoFile.PackedFixed64Extension);
+      registry.Add(UnitTestProtoFile.PackedSfixed32Extension);
+      registry.Add(UnitTestProtoFile.PackedSfixed64Extension);
+      registry.Add(UnitTestProtoFile.PackedFloatExtension);
+      registry.Add(UnitTestProtoFile.PackedDoubleExtension);
+      registry.Add(UnitTestProtoFile.PackedBoolExtension);
+      registry.Add(UnitTestProtoFile.PackedEnumExtension);
     }
 
     internal static string ReadTextFromFile(string filePath) {
@@ -653,6 +668,18 @@ namespace Google.ProtocolBuffers {
       return builder.Build();
     }
 
+    public static TestPackedTypes GetPackedSet() {
+      TestPackedTypes.Builder builder = TestPackedTypes.CreateBuilder();
+      SetPackedFields(builder);
+      return builder.Build();
+    }
+
+    public static TestPackedExtensions GetPackedExtensionsSet() {
+      TestPackedExtensions.Builder builder = TestPackedExtensions.CreateBuilder();
+      SetPackedExtensions(builder);
+      return builder.Build();
+    }
+
     /// <summary>
     /// Sets every field of the specified builder to the values expected by
     /// AssertAllExtensionsSet.
@@ -1373,6 +1400,184 @@ namespace Google.ProtocolBuffers {
       Assert.AreEqual("123", message.GetExtension(UnitTestProtoFile.DefaultCordExtension));
     }
 
+    /// <summary>
+    /// Set every field of the specified message to a unique value.
+    /// </summary>
+    public static void SetPackedFields(TestPackedTypes.Builder message) {
+      message.AddPackedInt32(601);
+      message.AddPackedInt64(602);
+      message.AddPackedUint32(603);
+      message.AddPackedUint64(604);
+      message.AddPackedSint32(605);
+      message.AddPackedSint64(606);
+      message.AddPackedFixed32(607);
+      message.AddPackedFixed64(608);
+      message.AddPackedSfixed32(609);
+      message.AddPackedSfixed64(610);
+      message.AddPackedFloat(611);
+      message.AddPackedDouble(612);
+      message.AddPackedBool(true);
+      message.AddPackedEnum(ForeignEnum.FOREIGN_BAR);
+      // Add a second one of each field.
+      message.AddPackedInt32(701);
+      message.AddPackedInt64(702);
+      message.AddPackedUint32(703);
+      message.AddPackedUint64(704);
+      message.AddPackedSint32(705);
+      message.AddPackedSint64(706);
+      message.AddPackedFixed32(707);
+      message.AddPackedFixed64(708);
+      message.AddPackedSfixed32(709);
+      message.AddPackedSfixed64(710);
+      message.AddPackedFloat(711);
+      message.AddPackedDouble(712);
+      message.AddPackedBool(false);
+      message.AddPackedEnum(ForeignEnum.FOREIGN_BAZ);
+    }
+
+    /// <summary>
+    /// Asserts that all the fields of the specified message are set to the values assigned
+    /// in SetPackedFields.
+    /// </summary>
+    public static void AssertPackedFieldsSet(TestPackedTypes message) {
+      Assert.AreEqual(2, message.PackedInt32Count);
+      Assert.AreEqual(2, message.PackedInt64Count);
+      Assert.AreEqual(2, message.PackedUint32Count);
+      Assert.AreEqual(2, message.PackedUint64Count);
+      Assert.AreEqual(2, message.PackedSint32Count);
+      Assert.AreEqual(2, message.PackedSint64Count);
+      Assert.AreEqual(2, message.PackedFixed32Count);
+      Assert.AreEqual(2, message.PackedFixed64Count);
+      Assert.AreEqual(2, message.PackedSfixed32Count);
+      Assert.AreEqual(2, message.PackedSfixed64Count);
+      Assert.AreEqual(2, message.PackedFloatCount);
+      Assert.AreEqual(2, message.PackedDoubleCount);
+      Assert.AreEqual(2, message.PackedBoolCount);
+      Assert.AreEqual(2, message.PackedEnumCount);
+      Assert.AreEqual(601, message.GetPackedInt32(0));
+      Assert.AreEqual(602, message.GetPackedInt64(0));
+      Assert.AreEqual(603, message.GetPackedUint32(0));
+      Assert.AreEqual(604, message.GetPackedUint64(0));
+      Assert.AreEqual(605, message.GetPackedSint32(0));
+      Assert.AreEqual(606, message.GetPackedSint64(0));
+      Assert.AreEqual(607, message.GetPackedFixed32(0));
+      Assert.AreEqual(608, message.GetPackedFixed64(0));
+      Assert.AreEqual(609, message.GetPackedSfixed32(0));
+      Assert.AreEqual(610, message.GetPackedSfixed64(0));
+      Assert.AreEqual(611, message.GetPackedFloat(0), 0.0);
+      Assert.AreEqual(612, message.GetPackedDouble(0), 0.0);
+      Assert.AreEqual(true, message.GetPackedBool(0));
+      Assert.AreEqual(ForeignEnum.FOREIGN_BAR, message.GetPackedEnum(0));
+      Assert.AreEqual(701, message.GetPackedInt32(1));
+      Assert.AreEqual(702, message.GetPackedInt64(1));
+      Assert.AreEqual(703, message.GetPackedUint32(1));
+      Assert.AreEqual(704, message.GetPackedUint64(1));
+      Assert.AreEqual(705, message.GetPackedSint32(1));
+      Assert.AreEqual(706, message.GetPackedSint64(1));
+      Assert.AreEqual(707, message.GetPackedFixed32(1));
+      Assert.AreEqual(708, message.GetPackedFixed64(1));
+      Assert.AreEqual(709, message.GetPackedSfixed32(1));
+      Assert.AreEqual(710, message.GetPackedSfixed64(1));
+      Assert.AreEqual(711, message.GetPackedFloat(1), 0.0);
+      Assert.AreEqual(712, message.GetPackedDouble(1), 0.0);
+      Assert.AreEqual(false, message.GetPackedBool(1));
+      Assert.AreEqual(ForeignEnum.FOREIGN_BAZ, message.GetPackedEnum(1));
+    }
+
+    public static void SetPackedExtensions(TestPackedExtensions.Builder message) {
+      message.AddExtension(UnitTestProtoFile.PackedInt32Extension, 601);
+      message.AddExtension(UnitTestProtoFile.PackedInt64Extension, 602L);
+      message.AddExtension(UnitTestProtoFile.PackedUint32Extension, 603U);
+      message.AddExtension(UnitTestProtoFile.PackedUint64Extension, 604UL);
+      message.AddExtension(UnitTestProtoFile.PackedSint32Extension, 605);
+      message.AddExtension(UnitTestProtoFile.PackedSint64Extension, 606L);
+      message.AddExtension(UnitTestProtoFile.PackedFixed32Extension, 607U);
+      message.AddExtension(UnitTestProtoFile.PackedFixed64Extension, 608UL);
+      message.AddExtension(UnitTestProtoFile.PackedSfixed32Extension, 609);
+      message.AddExtension(UnitTestProtoFile.PackedSfixed64Extension, 610L);
+      message.AddExtension(UnitTestProtoFile.PackedFloatExtension, 611F);
+      message.AddExtension(UnitTestProtoFile.PackedDoubleExtension, 612D);
+      message.AddExtension(UnitTestProtoFile.PackedBoolExtension, true);
+      message.AddExtension(UnitTestProtoFile.PackedEnumExtension, ForeignEnum.FOREIGN_BAR);
+      // Add a second one of each field.
+      message.AddExtension(UnitTestProtoFile.PackedInt32Extension, 701);
+      message.AddExtension(UnitTestProtoFile.PackedInt64Extension, 702L);
+      message.AddExtension(UnitTestProtoFile.PackedUint32Extension, 703U);
+      message.AddExtension(UnitTestProtoFile.PackedUint64Extension, 704UL);
+      message.AddExtension(UnitTestProtoFile.PackedSint32Extension, 705);
+      message.AddExtension(UnitTestProtoFile.PackedSint64Extension, 706L);
+      message.AddExtension(UnitTestProtoFile.PackedFixed32Extension, 707U);
+      message.AddExtension(UnitTestProtoFile.PackedFixed64Extension, 708UL);
+      message.AddExtension(UnitTestProtoFile.PackedSfixed32Extension, 709);
+      message.AddExtension(UnitTestProtoFile.PackedSfixed64Extension, 710L);
+      message.AddExtension(UnitTestProtoFile.PackedFloatExtension, 711F);
+      message.AddExtension(UnitTestProtoFile.PackedDoubleExtension, 712D);
+      message.AddExtension(UnitTestProtoFile.PackedBoolExtension, false);
+      message.AddExtension(UnitTestProtoFile.PackedEnumExtension, ForeignEnum.FOREIGN_BAZ);
+    }
+
+    public static void AssertPackedExtensionsSet(TestPackedExtensions message) {
+      Assert.AreEqual(2, message.GetExtensionCount(UnitTestProtoFile.PackedInt32Extension));
+      Assert.AreEqual(2, message.GetExtensionCount(UnitTestProtoFile.PackedInt64Extension));
+      Assert.AreEqual(2, message.GetExtensionCount(UnitTestProtoFile.PackedUint32Extension));
+      Assert.AreEqual(2, message.GetExtensionCount(UnitTestProtoFile.PackedUint64Extension));
+      Assert.AreEqual(2, message.GetExtensionCount(UnitTestProtoFile.PackedSint32Extension));
+      Assert.AreEqual(2, message.GetExtensionCount(UnitTestProtoFile.PackedSint64Extension));
+      Assert.AreEqual(2, message.GetExtensionCount(UnitTestProtoFile.PackedFixed32Extension));
+      Assert.AreEqual(2, message.GetExtensionCount(UnitTestProtoFile.PackedFixed64Extension));
+      Assert.AreEqual(2, message.GetExtensionCount(UnitTestProtoFile.PackedSfixed32Extension));
+      Assert.AreEqual(2, message.GetExtensionCount(UnitTestProtoFile.PackedSfixed64Extension));
+      Assert.AreEqual(2, message.GetExtensionCount(UnitTestProtoFile.PackedFloatExtension));
+      Assert.AreEqual(2, message.GetExtensionCount(UnitTestProtoFile.PackedDoubleExtension));
+      Assert.AreEqual(2, message.GetExtensionCount(UnitTestProtoFile.PackedBoolExtension));
+      Assert.AreEqual(2, message.GetExtensionCount(UnitTestProtoFile.PackedEnumExtension));
+      Assert.AreEqual(601, message.GetExtension(UnitTestProtoFile.PackedInt32Extension, 0));
+      Assert.AreEqual(602L, message.GetExtension(UnitTestProtoFile.PackedInt64Extension, 0));
+      Assert.AreEqual(603, message.GetExtension(UnitTestProtoFile.PackedUint32Extension, 0));
+      Assert.AreEqual(604L, message.GetExtension(UnitTestProtoFile.PackedUint64Extension, 0));
+      Assert.AreEqual(605, message.GetExtension(UnitTestProtoFile.PackedSint32Extension, 0));
+      Assert.AreEqual(606L, message.GetExtension(UnitTestProtoFile.PackedSint64Extension, 0));
+      Assert.AreEqual(607, message.GetExtension(UnitTestProtoFile.PackedFixed32Extension, 0));
+      Assert.AreEqual(608L, message.GetExtension(UnitTestProtoFile.PackedFixed64Extension, 0));
+      Assert.AreEqual(609, message.GetExtension(UnitTestProtoFile.PackedSfixed32Extension, 0));
+      Assert.AreEqual(610L, message.GetExtension(UnitTestProtoFile.PackedSfixed64Extension, 0));
+      Assert.AreEqual(611F, message.GetExtension(UnitTestProtoFile.PackedFloatExtension, 0));
+      Assert.AreEqual(612D, message.GetExtension(UnitTestProtoFile.PackedDoubleExtension, 0));
+      Assert.AreEqual(true, message.GetExtension(UnitTestProtoFile.PackedBoolExtension, 0));
+      Assert.AreEqual(ForeignEnum.FOREIGN_BAR,
+                            message.GetExtension(UnitTestProtoFile.PackedEnumExtension, 0));
+      Assert.AreEqual(701, message.GetExtension(UnitTestProtoFile.PackedInt32Extension, 1));
+      Assert.AreEqual(702L, message.GetExtension(UnitTestProtoFile.PackedInt64Extension, 1));
+      Assert.AreEqual(703, message.GetExtension(UnitTestProtoFile.PackedUint32Extension, 1));
+      Assert.AreEqual(704L, message.GetExtension(UnitTestProtoFile.PackedUint64Extension, 1));
+      Assert.AreEqual(705, message.GetExtension(UnitTestProtoFile.PackedSint32Extension, 1));
+      Assert.AreEqual(706L, message.GetExtension(UnitTestProtoFile.PackedSint64Extension, 1));
+      Assert.AreEqual(707, message.GetExtension(UnitTestProtoFile.PackedFixed32Extension, 1));
+      Assert.AreEqual(708L, message.GetExtension(UnitTestProtoFile.PackedFixed64Extension, 1));
+      Assert.AreEqual(709, message.GetExtension(UnitTestProtoFile.PackedSfixed32Extension, 1));
+      Assert.AreEqual(710L, message.GetExtension(UnitTestProtoFile.PackedSfixed64Extension, 1));
+      Assert.AreEqual(711F, message.GetExtension(UnitTestProtoFile.PackedFloatExtension, 1));
+      Assert.AreEqual(712D, message.GetExtension(UnitTestProtoFile.PackedDoubleExtension, 1));
+      Assert.AreEqual(false, message.GetExtension(UnitTestProtoFile.PackedBoolExtension, 1));
+      Assert.AreEqual(ForeignEnum.FOREIGN_BAZ, message.GetExtension(UnitTestProtoFile.PackedEnumExtension, 1));
+    }
+
+    private static ByteString goldenPackedFieldsMessage = null;
+
+    /// <summary>
+    /// Get the bytes of the "golden packed fields message".  This is a serialized
+    /// TestPackedTypes with all fields set as they would be by SetPackedFields,
+    /// but it is loaded from a file on disk rather than generated dynamically.
+    /// The file is actually generated by C++ code, so testing against it verifies compatibility
+    /// with C++.
+    /// </summary>
+    public static ByteString GetGoldenPackedFieldsMessage() {
+      if (goldenPackedFieldsMessage == null) {
+        goldenPackedFieldsMessage = ReadBytesFromFile("golden_packed_fields_message");
+      }
+      return goldenPackedFieldsMessage;
+    }
+    
     /// <summary>
     /// Helper to construct a byte array from a bunch of bytes.
     /// </summary>

+ 36 - 4
src/ProtocolBuffers.Test/WireFormatTest.cs

@@ -62,12 +62,20 @@ namespace Google.ProtocolBuffers {
       TestUtil.AssertAllFieldsSet(message2);
     }
 
+    [Test]
+    public void SerializationPacked() {
+      TestPackedTypes message = TestUtil.GetPackedSet();
+      ByteString rawBytes = message.ToByteString();
+      Assert.AreEqual(rawBytes.Length, message.SerializedSize);
+      TestPackedTypes message2 = TestPackedTypes.ParseFrom(rawBytes);
+      TestUtil.AssertPackedFieldsSet(message2);
+    }
+
     [Test]
     public void SerializeExtensions() {
       // TestAllTypes and TestAllExtensions should have compatible wire formats,
-      // so if we serealize a TestAllExtensions then parse it as TestAllTypes
+      // so if we serialize a TestAllExtensions then parse it as TestAllTypes
       // it should work.
-
       TestAllExtensions message = TestUtil.GetAllExtensionsSet();
       ByteString rawBytes = message.ToByteString();
       Assert.AreEqual(rawBytes.Length, message.SerializedSize);
@@ -77,6 +85,19 @@ namespace Google.ProtocolBuffers {
       TestUtil.AssertAllFieldsSet(message2);
     }
 
+    [Test]
+    public void SerializePackedExtensions() {
+      // TestPackedTypes and TestPackedExtensions should have compatible wire
+      // formats; check that they serialize to the same string.
+      TestPackedExtensions message = TestUtil.GetPackedExtensionsSet();
+      ByteString rawBytes = message.ToByteString();
+
+      TestPackedTypes message2 = TestUtil.GetPackedSet();
+      ByteString rawBytes2 = message2.ToByteString();
+
+      Assert.AreEqual(rawBytes, rawBytes2);
+    }
+
     [Test]
     public void ParseExtensions() {
       // TestAllTypes and TestAllExtensions should have compatible wire formats,
@@ -90,12 +111,23 @@ namespace Google.ProtocolBuffers {
       TestUtil.RegisterAllExtensions(registry);
       registry = registry.AsReadOnly();
 
-      TestAllExtensions message2 =
-        TestAllExtensions.ParseFrom(rawBytes, registry);
+      TestAllExtensions message2 = TestAllExtensions.ParseFrom(rawBytes, registry);
 
       TestUtil.AssertAllExtensionsSet(message2);
     }
 
+    [Test]
+    public void ParsePackedExtensions() {
+      // Ensure that packed extensions can be properly parsed.
+      TestPackedExtensions message = TestUtil.GetPackedExtensionsSet();
+      ByteString rawBytes = message.ToByteString();
+
+      ExtensionRegistry registry = TestUtil.CreateExtensionRegistry();
+
+      TestPackedExtensions message2 = TestPackedExtensions.ParseFrom(rawBytes, registry);
+      TestUtil.AssertPackedExtensionsSet(message2);
+    }
+
     [Test]
     public void ExtensionsSerializedSize() {
       Assert.AreEqual(TestUtil.GetAllSet().SerializedSize, TestUtil.GetAllExtensionsSet().SerializedSize);

+ 28 - 4
src/ProtocolBuffers/AbstractMessage.cs

@@ -110,8 +110,21 @@ namespace Google.ProtocolBuffers {
         if (field.IsRepeated) {
           // We know it's an IList<T>, but not the exact type - so
           // IEnumerable is the best we can do. (C# generics aren't covariant yet.)
-          foreach (object element in (IEnumerable)entry.Value) {
-            output.WriteField(field.FieldType, field.FieldNumber, element);
+          IEnumerable valueList = (IEnumerable) entry.Value;
+          if (field.IsPacked) {
+            output.WriteTag(field.FieldNumber, WireFormat.WireType.LengthDelimited);
+            int dataSize = 0;
+            foreach (object element in valueList) {
+              dataSize += CodedOutputStream.ComputeFieldSizeNoTag(field.FieldType, element);
+            }
+            output.WriteRawVarint32((uint)dataSize);
+            foreach (object element in valueList) {
+              output.WriteFieldNoTag(field.FieldType, element);
+            }
+          } else {
+            foreach (object element in valueList) {
+              output.WriteField(field.FieldType, field.FieldNumber, element);
+            }
           }
         } else {
           output.WriteField(field.FieldType, field.FieldNumber, entry.Value);
@@ -136,8 +149,19 @@ namespace Google.ProtocolBuffers {
         foreach (KeyValuePair<FieldDescriptor, object> entry in AllFields) {
           FieldDescriptor field = entry.Key;
           if (field.IsRepeated) {
-            foreach (object element in (IEnumerable) entry.Value) {
-              size += CodedOutputStream.ComputeFieldSize(field.FieldType, field.FieldNumber, element);
+            IEnumerable valueList = (IEnumerable) entry.Value;
+            if (field.IsPacked) {
+              int dataSize = 0;
+              foreach (object element in valueList) {
+                dataSize += CodedOutputStream.ComputeFieldSizeNoTag(field.FieldType, element);
+              }
+              size += dataSize;
+              size += CodedOutputStream.ComputeTagSize(field.FieldNumber);
+              size += CodedOutputStream.ComputeRawVarint32Size((uint)dataSize);
+            } else {
+              foreach (object element in valueList) {
+                size += CodedOutputStream.ComputeFieldSize(field.FieldType, field.FieldNumber, element);
+              }
             }
           } else {
             size += CodedOutputStream.ComputeFieldSize(field.FieldType, field.FieldNumber, entry.Value);

+ 14 - 0
src/ProtocolBuffers/CodedInputStream.cs

@@ -608,6 +608,20 @@ namespace Google.ProtocolBuffers {
       RecomputeBufferSizeAfterLimit();
     }
 
+    /// <summary>
+    /// Returns whether or not all the data before the limit has been read.
+    /// </summary>
+    /// <returns></returns>
+    public bool ReachedLimit {
+      get {
+        if (currentLimit == int.MaxValue) {
+          return false;
+        }
+        int currentAbsolutePosition = totalBytesRetired + bufferPos;
+        return currentAbsolutePosition >= currentLimit;
+      }
+    }
+    
     /// <summary>
     /// Called when buffer is empty to read more bytes from the
     /// input.  If <paramref name="mustSucceed"/> is true, RefillBuffer() gurantees that

+ 347 - 16
src/ProtocolBuffers/CodedOutputStream.cs

@@ -298,6 +298,156 @@ namespace Google.ProtocolBuffers {
       }
     }
 
+    public void WriteFieldNoTag(FieldType fieldType, object value) {
+      switch (fieldType) {
+        case FieldType.Double: WriteDoubleNoTag((double)value); break;
+        case FieldType.Float: WriteFloatNoTag((float)value); break;
+        case FieldType.Int64: WriteInt64NoTag((long)value); break;
+        case FieldType.UInt64: WriteUInt64NoTag((ulong)value); break;
+        case FieldType.Int32: WriteInt32NoTag((int)value); break;
+        case FieldType.Fixed64: WriteFixed64NoTag((ulong)value); break;
+        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.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);
+          break;
+      }
+    }
+    #endregion
+
+    #region Writing of values without tags
+    /// <summary>
+    /// Writes a double field value, including tag, to the stream.
+    /// </summary>
+    public void WriteDoubleNoTag(double value) {
+      WriteRawLittleEndian64((ulong)BitConverter.DoubleToInt64Bits(value));
+    }
+
+    /// <summary>
+    /// Writes a float field value, without a tag, to the stream.
+    /// </summary>
+    public void WriteFloatNoTag(float value) {
+      // TODO(jonskeet): Test this on different endiannesses
+      byte[] rawBytes = BitConverter.GetBytes(value);
+      uint asInteger = BitConverter.ToUInt32(rawBytes, 0);
+      WriteRawLittleEndian32(asInteger);
+    }
+
+    /// <summary>
+    /// Writes a uint64 field value, without a tag, to the stream.
+    /// </summary>
+    public void WriteUInt64NoTag(ulong value) {
+      WriteRawVarint64(value);
+    }
+
+    /// <summary>
+    /// Writes an int64 field value, without a tag, to the stream.
+    /// </summary>
+    public void WriteInt64NoTag(long value) {
+      WriteRawVarint64((ulong)value);
+    }
+
+    /// <summary>
+    /// Writes an int32 field value, without a tag, to the stream.
+    /// </summary>
+    public void WriteInt32NoTag(int value) {
+      if (value >= 0) {
+        WriteRawVarint32((uint)value);
+      } else {
+        // Must sign-extend.
+        WriteRawVarint64((ulong)value);
+      }
+    }
+
+    /// <summary>
+    /// Writes a fixed64 field value, without a tag, to the stream.
+    /// </summary>
+    public void WriteFixed64NoTag(ulong value) {
+      WriteRawLittleEndian64(value);
+    }
+
+    /// <summary>
+    /// Writes a fixed32 field value, without a tag, to the stream.
+    /// </summary>
+    public void WriteFixed32NoTag(uint value) {
+      WriteRawLittleEndian32(value);
+    }
+
+    /// <summary>
+    /// Writes a bool field value, without a tag, to the stream.
+    /// </summary>
+    public void WriteBoolNoTag(bool value) {
+      WriteRawByte(value ? (byte)1 : (byte)0);
+    }
+
+    /// <summary>
+    /// Writes a string field value, without a tag, to the stream.
+    /// </summary>
+    public void WriteStringNoTag(string value) {
+      // Optimise the case where we have enough space to write
+      // the string directly to the buffer, which should be common.
+      int length = Encoding.UTF8.GetByteCount(value);
+      WriteRawVarint32((uint)length);
+      if (limit - position >= length) {
+        Encoding.UTF8.GetBytes(value, 0, value.Length, buffer, position);
+        position += length;
+      } else {
+        byte[] bytes = Encoding.UTF8.GetBytes(value);
+        WriteRawBytes(bytes);
+      }
+    }
+
+    /// <summary>
+    /// Writes a group field value, without a tag, to the stream.
+    /// </summary>
+    public void WriteGroupNoTag(IMessage value) {
+      value.WriteTo(this);
+    }
+
+    public void WriteMessageNoTag(IMessage value) {
+      WriteRawVarint32((uint)value.SerializedSize);
+      value.WriteTo(this);
+    }
+
+    public void WriteBytesNoTag(ByteString value) {
+      // TODO(jonskeet): Optimise this! (No need to copy the bytes twice.)
+      byte[] bytes = value.ToByteArray();
+      WriteRawVarint32((uint)bytes.Length);
+      WriteRawBytes(bytes);
+    }
+
+    public void WriteUInt32NoTag(uint value) {
+      WriteRawVarint32(value);
+    }
+
+    public void WriteEnumNoTag(int value) {
+      WriteRawVarint32((uint)value);
+    }
+
+    public void WriteSFixed32NoTag(int value) {
+      WriteRawLittleEndian32((uint)value);
+    }
+
+    public void WriteSFixed64NoTag(long value) {
+      WriteRawLittleEndian64((ulong)value);
+    }
+
+    public void WriteSInt32NoTag(int value) {
+      WriteRawVarint32(EncodeZigZag32(value));
+    }
+
+    public void WriteSInt64NoTag(long value) {
+      WriteRawVarint64(EncodeZigZag64(value));
+    }
+
     #endregion
 
     #region Underlying writing primitives
@@ -583,8 +733,7 @@ namespace Google.ProtocolBuffers {
     /// sint32 field, including the tag.
     /// </summary>
     public static int ComputeSInt32Size(int fieldNumber, int value) {
-      return ComputeTagSize(fieldNumber) +
-             ComputeRawVarint32Size(EncodeZigZag32(value));
+      return ComputeTagSize(fieldNumber) + ComputeRawVarint32Size(EncodeZigZag32(value));
     }
 
     /// <summary>
@@ -592,8 +741,169 @@ namespace Google.ProtocolBuffers {
     /// sint64 field, including the tag.
     /// </summary>
     public static int ComputeSInt64Size(int fieldNumber, long value) {
-      return ComputeTagSize(fieldNumber) +
-             ComputeRawVarint64Size(EncodeZigZag64(value));
+      return ComputeTagSize(fieldNumber) + ComputeRawVarint64Size(EncodeZigZag64(value));
+    }
+
+    /// <summary>
+    /// Compute the number of bytes that would be needed to encode a
+    /// double field, including the tag.
+    /// </summary>
+    public static int ComputeDoubleSizeNoTag(double value) {
+      return LittleEndian64Size;
+    }
+
+    /// <summary>
+    /// Compute the number of bytes that would be needed to encode a
+    /// float field, including the tag.
+    /// </summary>
+    public static int ComputeFloatSizeNoTag(float value) {
+      return LittleEndian32Size;
+    }
+
+    /// <summary>
+    /// Compute the number of bytes that would be needed to encode a
+    /// uint64 field, including the tag.
+    /// </summary>
+    public static int ComputeUInt64SizeNoTag(ulong value) {
+      return ComputeRawVarint64Size(value);
+    }
+
+    /// <summary>
+    /// Compute the number of bytes that would be needed to encode an
+    /// int64 field, including the tag.
+    /// </summary>
+    public static int ComputeInt64SizeNoTag(long value) {
+      return ComputeRawVarint64Size((ulong)value);
+    }
+
+    /// <summary>
+    /// Compute the number of bytes that would be needed to encode an
+    /// int32 field, including the tag.
+    /// </summary>
+    public static int ComputeInt32SizeNoTag(int value) {
+      if (value >= 0) {
+        return ComputeRawVarint32Size((uint)value);
+      } else {
+        // Must sign-extend.
+        return 10;
+      }
+    }
+
+    /// <summary>
+    /// Compute the number of bytes that would be needed to encode a
+    /// fixed64 field, including the tag.
+    /// </summary>
+    public static int ComputeFixed64SizeNoTag(ulong value) {
+      return LittleEndian64Size;
+    }
+
+    /// <summary>
+    /// Compute the number of bytes that would be needed to encode a
+    /// fixed32 field, including the tag.
+    /// </summary>
+    public static int ComputeFixed32SizeNoTag(uint value) {
+      return LittleEndian32Size;
+    }
+
+    /// <summary>
+    /// Compute the number of bytes that would be needed to encode a
+    /// bool field, including the tag.
+    /// </summary>
+    public static int ComputeBoolSizeNoTag(bool value) {
+      return 1;
+    }
+
+    /// <summary>
+    /// Compute the number of bytes that would be needed to encode a
+    /// string field, including the tag.
+    /// </summary>
+    public static int ComputeStringSizeNoTag(String value) {
+      int byteArraySize = Encoding.UTF8.GetByteCount(value);
+      return ComputeRawVarint32Size((uint)byteArraySize) +
+             byteArraySize;
+    }
+
+    /// <summary>
+    /// Compute the number of bytes that would be needed to encode a
+    /// group field, including the tag.
+    /// </summary>
+    public static int ComputeGroupSizeNoTag(IMessage value) {
+      return value.SerializedSize;
+    }
+
+    /// <summary>
+    /// Compute the number of bytes that would be needed to encode a
+    /// group field represented by an UnknownFieldSet, including the tag.
+    /// </summary>
+    public static int ComputeUnknownGroupSizeNoTag(UnknownFieldSet value) {
+      return value.SerializedSize;
+    }
+
+    /// <summary>
+    /// Compute the number of bytes that would be needed to encode an
+    /// embedded message field, including the tag.
+    /// </summary>
+    public static int ComputeMessageSizeNoTag(IMessage value) {
+      int size = value.SerializedSize;
+      return ComputeRawVarint32Size((uint)size) + size;
+    }
+
+    /// <summary>
+    /// Compute the number of bytes that would be needed to encode a
+    /// bytes field, including the tag.
+    /// </summary>
+    public static int ComputeBytesSizeNoTag(ByteString value) {
+      return ComputeRawVarint32Size((uint)value.Length) +
+             value.Length;
+    }
+
+    /// <summary>
+    /// Compute the number of bytes that would be needed to encode a
+    /// uint32 field, including the tag.
+    /// </summary>
+    public static int ComputeUInt32SizeNoTag(uint value) {
+      return ComputeRawVarint32Size(value);
+    }
+
+    /// <summary>
+    /// Compute the number of bytes that would be needed to encode a
+    /// enum field, including the tag. The caller is responsible for
+    /// converting the enum value to its numeric value.
+    /// </summary>
+    public static int ComputeEnumSizeNoTag(int value) {
+      return ComputeRawVarint32Size((uint)value);
+    }
+
+    /// <summary>
+    /// Compute the number of bytes that would be needed to encode an
+    /// sfixed32 field, including the tag.
+    /// </summary>
+    public static int ComputeSFixed32SizeNoTag(int value) {
+      return LittleEndian32Size;
+    }
+
+    /// <summary>
+    /// Compute the number of bytes that would be needed to encode an
+    /// sfixed64 field, including the tag.
+    /// </summary>
+    public static int ComputeSFixed64SizeNoTag(long value) {
+      return LittleEndian64Size;
+    }
+
+    /// <summary>
+    /// Compute the number of bytes that would be needed to encode an
+    /// sint32 field, including the tag.
+    /// </summary>
+    public static int ComputeSInt32SizeNoTag(int value) {
+      return ComputeRawVarint32Size(EncodeZigZag32(value));
+    }
+
+    /// <summary>
+    /// Compute the number of bytes that would be needed to encode an
+    /// sint64 field, including the tag.
+    /// </summary>
+    public static int ComputeSInt64SizeNoTag(long value) {
+      return ComputeRawVarint64Size(EncodeZigZag64(value));
     }
 
     /*
@@ -650,18 +960,10 @@ namespace Google.ProtocolBuffers {
       return 10;
     }
 
-
-    /*
-     * Compute the number of bytes that would be needed to encode a
-     * field of arbitrary type, including tag, to the stream.
-     *
-     * @param type   The field's type.
-     * @param number The field's number.
-     * @param value  Object representing the field's value.  Must be of the exact
-     *               type which would be returned by
-     *               {@link Message#getField(FieldDescriptor)} for
-     *               this field.
-     */
+    /// <summary>
+    /// Compute the number of bytes that would be needed to encode a
+    /// field of arbitrary type, including the tag, to the stream.
+    /// </summary>
     public static int ComputeFieldSize(FieldType fieldType, int fieldNumber, Object value) {
       switch (fieldType) {
         case FieldType.Double: return ComputeDoubleSize(fieldNumber, (double)value);
@@ -687,6 +989,35 @@ namespace Google.ProtocolBuffers {
       }
     }
 
+    /// <summary>
+    /// Compute the number of bytes that would be needed to encode a
+    /// field of arbitrary type, excluding the tag, to the stream.
+    /// </summary>
+    public static int ComputeFieldSizeNoTag(FieldType fieldType, Object value) {
+      switch (fieldType) {
+        case FieldType.Double: return ComputeDoubleSizeNoTag((double)value);
+        case FieldType.Float: return ComputeFloatSizeNoTag((float)value);
+        case FieldType.Int64: return ComputeInt64SizeNoTag((long)value);
+        case FieldType.UInt64: return ComputeUInt64SizeNoTag((ulong)value);
+        case FieldType.Int32: return ComputeInt32SizeNoTag((int)value);
+        case FieldType.Fixed64: return ComputeFixed64SizeNoTag((ulong)value);
+        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.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);
+        default:
+          throw new ArgumentOutOfRangeException("Invalid field type " + fieldType);
+      }
+    }
+
     /// <summary>
     /// Compute the number of bytes that would be needed to encode a tag.
     /// </summary>

+ 73 - 26
src/ProtocolBuffers/DescriptorProtos/DescriptorProtoFile.cs

@@ -70,27 +70,27 @@ namespace Google.ProtocolBuffers.DescriptorProtos {
         "AioJCOgHEICAgIACIogBCg5NZXNzYWdlT3B0aW9ucxImChdtZXNzYWdlX3Nl" + 
         "dF93aXJlX2Zvcm1hdBgBIAEoCDoFZmFsc2USQwoUdW5pbnRlcnByZXRlZF9v" + 
         "cHRpb24Y5wcgAygLMiQuZ29vZ2xlLnByb3RvYnVmLlVuaW50ZXJwcmV0ZWRP" + 
-        "cHRpb24qCQjoBxCAgICAAiLVAQoMRmllbGRPcHRpb25zEjIKBWN0eXBlGAEg" + 
-        "ASgOMiMuZ29vZ2xlLnByb3RvYnVmLkZpZWxkT3B0aW9ucy5DVHlwZRIcChRl" + 
-        "eHBlcmltZW50YWxfbWFwX2tleRgJIAEoCRJDChR1bmludGVycHJldGVkX29w" + 
-        "dGlvbhjnByADKAsyJC5nb29nbGUucHJvdG9idWYuVW5pbnRlcnByZXRlZE9w" + 
-        "dGlvbiIjCgVDVHlwZRIICgRDT1JEEAESEAoMU1RSSU5HX1BJRUNFEAIqCQjo" + 
-        "BxCAgICAAiJdCgtFbnVtT3B0aW9ucxJDChR1bmludGVycHJldGVkX29wdGlv" + 
-        "bhjnByADKAsyJC5nb29nbGUucHJvdG9idWYuVW5pbnRlcnByZXRlZE9wdGlv" + 
-        "bioJCOgHEICAgIACImIKEEVudW1WYWx1ZU9wdGlvbnMSQwoUdW5pbnRlcnBy" + 
-        "ZXRlZF9vcHRpb24Y5wcgAygLMiQuZ29vZ2xlLnByb3RvYnVmLlVuaW50ZXJw" + 
-        "cmV0ZWRPcHRpb24qCQjoBxCAgICAAiJgCg5TZXJ2aWNlT3B0aW9ucxJDChR1" + 
-        "bmludGVycHJldGVkX29wdGlvbhjnByADKAsyJC5nb29nbGUucHJvdG9idWYu" + 
-        "VW5pbnRlcnByZXRlZE9wdGlvbioJCOgHEICAgIACIl8KDU1ldGhvZE9wdGlv" + 
-        "bnMSQwoUdW5pbnRlcnByZXRlZF9vcHRpb24Y5wcgAygLMiQuZ29vZ2xlLnBy" + 
-        "b3RvYnVmLlVuaW50ZXJwcmV0ZWRPcHRpb24qCQjoBxCAgICAAiKFAgoTVW5p" + 
-        "bnRlcnByZXRlZE9wdGlvbhI7CgRuYW1lGAIgAygLMi0uZ29vZ2xlLnByb3Rv" + 
-        "YnVmLlVuaW50ZXJwcmV0ZWRPcHRpb24uTmFtZVBhcnQSGAoQaWRlbnRpZmll" + 
-        "cl92YWx1ZRgDIAEoCRIaChJwb3NpdGl2ZV9pbnRfdmFsdWUYBCABKAQSGgoS" + 
-        "bmVnYXRpdmVfaW50X3ZhbHVlGAUgASgDEhQKDGRvdWJsZV92YWx1ZRgGIAEo" + 
-        "ARIUCgxzdHJpbmdfdmFsdWUYByABKAwaMwoITmFtZVBhcnQSEQoJbmFtZV9w" + 
-        "YXJ0GAEgAigJEhQKDGlzX2V4dGVuc2lvbhgCIAIoCEIpChNjb20uZ29vZ2xl" + 
-        "LnByb3RvYnVmQhBEZXNjcmlwdG9yUHJvdG9zSAE="),
+        "cHRpb24qCQjoBxCAgICAAiLlAQoMRmllbGRPcHRpb25zEjIKBWN0eXBlGAEg" + 
+        "ASgOMiMuZ29vZ2xlLnByb3RvYnVmLkZpZWxkT3B0aW9ucy5DVHlwZRIOCgZw" + 
+        "YWNrZWQYAiABKAgSHAoUZXhwZXJpbWVudGFsX21hcF9rZXkYCSABKAkSQwoU" + 
+        "dW5pbnRlcnByZXRlZF9vcHRpb24Y5wcgAygLMiQuZ29vZ2xlLnByb3RvYnVm" + 
+        "LlVuaW50ZXJwcmV0ZWRPcHRpb24iIwoFQ1R5cGUSCAoEQ09SRBABEhAKDFNU" + 
+        "UklOR19QSUVDRRACKgkI6AcQgICAgAIiXQoLRW51bU9wdGlvbnMSQwoUdW5p" + 
+        "bnRlcnByZXRlZF9vcHRpb24Y5wcgAygLMiQuZ29vZ2xlLnByb3RvYnVmLlVu" + 
+        "aW50ZXJwcmV0ZWRPcHRpb24qCQjoBxCAgICAAiJiChBFbnVtVmFsdWVPcHRp" + 
+        "b25zEkMKFHVuaW50ZXJwcmV0ZWRfb3B0aW9uGOcHIAMoCzIkLmdvb2dsZS5w" + 
+        "cm90b2J1Zi5VbmludGVycHJldGVkT3B0aW9uKgkI6AcQgICAgAIiYAoOU2Vy" + 
+        "dmljZU9wdGlvbnMSQwoUdW5pbnRlcnByZXRlZF9vcHRpb24Y5wcgAygLMiQu" + 
+        "Z29vZ2xlLnByb3RvYnVmLlVuaW50ZXJwcmV0ZWRPcHRpb24qCQjoBxCAgICA" + 
+        "AiJfCg1NZXRob2RPcHRpb25zEkMKFHVuaW50ZXJwcmV0ZWRfb3B0aW9uGOcH" + 
+        "IAMoCzIkLmdvb2dsZS5wcm90b2J1Zi5VbmludGVycHJldGVkT3B0aW9uKgkI" + 
+        "6AcQgICAgAIihQIKE1VuaW50ZXJwcmV0ZWRPcHRpb24SOwoEbmFtZRgCIAMo" + 
+        "CzItLmdvb2dsZS5wcm90b2J1Zi5VbmludGVycHJldGVkT3B0aW9uLk5hbWVQ" + 
+        "YXJ0EhgKEGlkZW50aWZpZXJfdmFsdWUYAyABKAkSGgoScG9zaXRpdmVfaW50" + 
+        "X3ZhbHVlGAQgASgEEhoKEm5lZ2F0aXZlX2ludF92YWx1ZRgFIAEoAxIUCgxk" + 
+        "b3VibGVfdmFsdWUYBiABKAESFAoMc3RyaW5nX3ZhbHVlGAcgASgMGjMKCE5h" + 
+        "bWVQYXJ0EhEKCW5hbWVfcGFydBgBIAIoCRIUCgxpc19leHRlbnNpb24YAiAC" + 
+        "KAhCKQoTY29tLmdvb2dsZS5wcm90b2J1ZkIQRGVzY3JpcHRvclByb3Rvc0gB"),
         new pbd::FileDescriptor[] {
         });
     #endregion
@@ -155,7 +155,7 @@ namespace Google.ProtocolBuffers.DescriptorProtos {
         = Descriptor.MessageTypes[10];
     internal static pb::FieldAccess.FieldAccessorTable<global::Google.ProtocolBuffers.DescriptorProtos.FieldOptions, global::Google.ProtocolBuffers.DescriptorProtos.FieldOptions.Builder> internal__static_google_protobuf_FieldOptions__FieldAccessorTable
         = new pb::FieldAccess.FieldAccessorTable<global::Google.ProtocolBuffers.DescriptorProtos.FieldOptions, global::Google.ProtocolBuffers.DescriptorProtos.FieldOptions.Builder>(internal__static_google_protobuf_FieldOptions__Descriptor,
-            new string[] { "Ctype", "ExperimentalMapKey", "UninterpretedOption", });
+            new string[] { "Ctype", "Packed", "ExperimentalMapKey", "UninterpretedOption", });
     internal static readonly pbd::MessageDescriptor internal__static_google_protobuf_EnumOptions__Descriptor
         = Descriptor.MessageTypes[11];
     internal static pb::FieldAccess.FieldAccessorTable<global::Google.ProtocolBuffers.DescriptorProtos.EnumOptions, global::Google.ProtocolBuffers.DescriptorProtos.EnumOptions.Builder> internal__static_google_protobuf_EnumOptions__FieldAccessorTable
@@ -541,8 +541,10 @@ namespace Google.ProtocolBuffers.DescriptorProtos {
       if (HasPackage) {
         output.WriteString(2, Package);
       }
-      foreach (string element in DependencyList) {
-        output.WriteString(3, element);
+      if (dependency_.Count > 0) {
+        foreach (string element in dependency_) {
+          output.WriteString(3, element);
+        }
       }
       foreach (global::Google.ProtocolBuffers.DescriptorProtos.DescriptorProto element in MessageTypeList) {
         output.WriteMessage(4, element);
@@ -575,8 +577,13 @@ namespace Google.ProtocolBuffers.DescriptorProtos {
         if (HasPackage) {
           size += pb::CodedOutputStream.ComputeStringSize(2, Package);
         }
-        foreach (string element in DependencyList) {
-          size += pb::CodedOutputStream.ComputeStringSize(3, element);
+        {
+          int dataSize = 0;
+          foreach (string element in DependencyList) {
+            dataSize += pb::CodedOutputStream.ComputeStringSizeNoTag(element);
+          }
+          size += dataSize;
+          size += 1 * dependency_.Count;
         }
         foreach (global::Google.ProtocolBuffers.DescriptorProtos.DescriptorProto element in MessageTypeList) {
           size += pb::CodedOutputStream.ComputeMessageSize(4, element);
@@ -4413,6 +4420,15 @@ namespace Google.ProtocolBuffers.DescriptorProtos {
       get { return ctype_; }
     }
     
+    private bool hasPacked;
+    private bool packed_ = false;
+    public bool HasPacked {
+      get { return hasPacked; }
+    }
+    public bool Packed {
+      get { return packed_; }
+    }
+    
     private bool hasExperimentalMapKey;
     private string experimentalMapKey_ = "";
     public bool HasExperimentalMapKey {
@@ -4448,6 +4464,9 @@ namespace Google.ProtocolBuffers.DescriptorProtos {
       if (HasCtype) {
         output.WriteEnum(1, (int) Ctype);
       }
+      if (HasPacked) {
+        output.WriteBool(2, Packed);
+      }
       if (HasExperimentalMapKey) {
         output.WriteString(9, ExperimentalMapKey);
       }
@@ -4468,6 +4487,9 @@ namespace Google.ProtocolBuffers.DescriptorProtos {
         if (HasCtype) {
           size += pb::CodedOutputStream.ComputeEnumSize(1, (int) Ctype);
         }
+        if (HasPacked) {
+          size += pb::CodedOutputStream.ComputeBoolSize(2, Packed);
+        }
         if (HasExperimentalMapKey) {
           size += pb::CodedOutputStream.ComputeStringSize(9, ExperimentalMapKey);
         }
@@ -4561,6 +4583,9 @@ namespace Google.ProtocolBuffers.DescriptorProtos {
         if (other.HasCtype) {
           Ctype = other.Ctype;
         }
+        if (other.HasPacked) {
+          Packed = other.Packed;
+        }
         if (other.HasExperimentalMapKey) {
           ExperimentalMapKey = other.ExperimentalMapKey;
         }
@@ -4601,6 +4626,10 @@ namespace Google.ProtocolBuffers.DescriptorProtos {
               }
               break;
             }
+            case 16: {
+              Packed = input.ReadBool();
+              break;
+            }
             case 74: {
               ExperimentalMapKey = input.ReadString();
               break;
@@ -4634,6 +4663,24 @@ namespace Google.ProtocolBuffers.DescriptorProtos {
         return this;
       }
       
+      public bool HasPacked {
+        get { return result.HasPacked; }
+      }
+      public bool Packed {
+        get { return result.Packed; }
+        set { SetPacked(value); }
+      }
+      public Builder SetPacked(bool value) {
+        result.hasPacked = true;
+        result.packed_ = value;
+        return this;
+      }
+      public Builder ClearPacked() {
+        result.hasPacked = false;
+        result.packed_ = false;
+        return this;
+      }
+      
       public bool HasExperimentalMapKey {
         get { return result.HasExperimentalMapKey; }
       }

+ 4 - 0
src/ProtocolBuffers/Descriptors/FieldDescriptor.cs

@@ -176,6 +176,10 @@ namespace Google.ProtocolBuffers.Descriptors {
       get { return Proto.Label == FieldDescriptorProto.Types.Label.LABEL_REPEATED; }
     }
 
+    public bool IsPacked {
+      get { return Proto.Options.Packed; }
+    }
+
     /// <valule>
     /// Indicates whether or not the field had an explicitly-defined default value.
     /// </value>

+ 29 - 5
src/ProtocolBuffers/FieldSet.cs

@@ -368,8 +368,23 @@ namespace Google.ProtocolBuffers {
         output.WriteMessageSetExtension(field.FieldNumber, (IMessage) value);
       } else {
         if (field.IsRepeated) {
-          foreach (object element in (IEnumerable) value) {
-            output.WriteField(field.FieldType, field.FieldNumber, element);
+          IEnumerable valueList = (IEnumerable) value;
+          if (field.IsPacked) {
+            output.WriteTag(field.FieldNumber, WireFormat.WireType.LengthDelimited);
+            // Compute the total data size so the length can be written.
+            int dataSize = 0;
+            foreach (object element in valueList) {
+              dataSize += CodedOutputStream.ComputeFieldSizeNoTag(field.FieldType, element);
+            }
+            output.WriteRawVarint32((uint)dataSize);
+            // Write the data itself, without any tags.
+            foreach (object element in valueList) {
+              output.WriteFieldNoTag(field.FieldType, element);
+            }
+          } else {
+            foreach (object element in valueList) {
+              output.WriteField(field.FieldType, field.FieldNumber, element);
+            }
           }
         } else {
           output.WriteField(field.FieldType, field.FieldNumber, value);
@@ -389,11 +404,20 @@ namespace Google.ProtocolBuffers {
           object value = entry.Value;
 
           if (field.IsExtension && field.ContainingType.Options.MessageSetWireFormat) {
-            size += CodedOutputStream.ComputeMessageSetExtensionSize(field.FieldNumber, (IMessage) value);
+            size += CodedOutputStream.ComputeMessageSetExtensionSize(field.FieldNumber, (IMessage)value);
           } else {
             if (field.IsRepeated) {
-              foreach (object element in (IEnumerable) value) {
-                size += CodedOutputStream.ComputeFieldSize(field.FieldType, field.FieldNumber, element);
+              IEnumerable valueList = (IEnumerable)value;
+              if (field.IsPacked) {
+                int dataSize = 0;
+                foreach (object element in valueList) {
+                  dataSize += CodedOutputStream.ComputeFieldSizeNoTag(field.FieldType, element);
+                }
+                size += dataSize + CodedOutputStream.ComputeTagSize(field.FieldNumber) + CodedOutputStream.ComputeRawVarint32Size((uint)dataSize);
+              } else {
+                foreach (object element in valueList) {
+                  size += CodedOutputStream.ComputeFieldSize(field.FieldType, field.FieldNumber, element);
+                }
               }
             } else {
               size += CodedOutputStream.ComputeFieldSize(field.FieldType, field.FieldNumber, value);

+ 58 - 35
src/ProtocolBuffers/UnknownFieldSet.cs

@@ -497,50 +497,73 @@ namespace Google.ProtocolBuffers {
         }
 
         // Unknown field or wrong wire type. Skip.
-        if (field == null || wireType != WireFormat.GetWireType(field.FieldType)) {
+        if (field == null || wireType != WireFormat.GetWireType(field)) {
           return MergeFieldFrom(tag, input);
         }
 
-        object value;
-        switch (field.FieldType) {
-          case FieldType.Group:
-          case FieldType.Message: {
-              IBuilder subBuilder;
-              if (defaultFieldInstance != null) {
-                subBuilder = defaultFieldInstance.WeakCreateBuilderForType();
-              } else {
-                subBuilder = builder.CreateBuilderForField(field);
-              }
-              if (!field.IsRepeated) {
-                subBuilder.WeakMergeFrom((IMessage)builder[field]);
-              }
-              if (field.FieldType == FieldType.Group) {
-                input.ReadGroup(field.FieldNumber, subBuilder, extensionRegistry);
-              } else {
-                input.ReadMessage(subBuilder, extensionRegistry);
-              }
-              value = subBuilder.WeakBuild();
-              break;
-            }
-          case FieldType.Enum: {
+        if (field.IsPacked) {
+          int length = (int)input.ReadRawVarint32();
+          int limit = input.PushLimit(length);
+          if (field.FieldType == FieldType.Enum) {
+            while (!input.ReachedLimit) {
               int rawValue = input.ReadEnum();
-              value = field.EnumType.FindValueByNumber(rawValue);
-              // If the number isn't recognized as a valid value for this enum,
-              // drop it.
+              object value = field.EnumType.FindValueByNumber(rawValue);
               if (value == null) {
-                MergeVarintField(fieldNumber, (ulong)rawValue);
+                // If the number isn't recognized as a valid value for this
+                // enum, drop it (don't even add it to unknownFields).
                 return true;
               }
-              break;
+              builder.WeakAddRepeatedField(field, value);
             }
-          default:
-            value = input.ReadPrimitiveField(field.FieldType);
-            break;
-        }
-        if (field.IsRepeated) {
-          builder.WeakAddRepeatedField(field, value);
+          } else {
+            while (!input.ReachedLimit) {
+              Object value = input.ReadPrimitiveField(field.FieldType);
+              builder.WeakAddRepeatedField(field, value);
+            }
+          }
+          input.PopLimit(limit);
         } else {
-          builder[field] = value;
+          object value;
+          switch (field.FieldType) {
+            case FieldType.Group:
+            case FieldType.Message: {
+                IBuilder subBuilder;
+                if (defaultFieldInstance != null) {
+                  subBuilder = defaultFieldInstance.WeakCreateBuilderForType();
+                } else {
+                  subBuilder = builder.CreateBuilderForField(field);
+                }
+                if (!field.IsRepeated) {
+                  subBuilder.WeakMergeFrom((IMessage)builder[field]);
+                }
+                if (field.FieldType == FieldType.Group) {
+                  input.ReadGroup(field.FieldNumber, subBuilder, extensionRegistry);
+                } else {
+                  input.ReadMessage(subBuilder, extensionRegistry);
+                }
+                value = subBuilder.WeakBuild();
+                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) {
+                  MergeVarintField(fieldNumber, (ulong)rawValue);
+                  return true;
+                }
+                break;
+              }
+            default:
+              value = input.ReadPrimitiveField(field.FieldType);
+              break;
+          }
+          if (field.IsRepeated) {
+            builder.WeakAddRepeatedField(field, value);
+          } else {
+            builder[field] = value;
+          }
         }
         return true;
       }

+ 25 - 0
src/ProtocolBuffers/WireFormat.cs

@@ -46,6 +46,19 @@ namespace Google.ProtocolBuffers {
   /// </para>
   /// </summary>
   public static class WireFormat {
+
+#region Fixed sizes.
+    // TODO(jonskeet): Move these somewhere else. They're messy. Consider making FieldType a smarter kind of enum
+    internal const int Fixed32Size = 4;
+    internal const int Fixed64Size = 8;
+    internal const int SFixed32Size = 4;
+    internal const int SFixed64Size = 8;
+    internal const int FloatSize = 4;
+    internal const int DoubleSize = 8;
+    internal const int BoolSize = 1;
+#endregion
+
+
     public enum WireType : uint {
       Varint = 0,
       Fixed64 = 1,
@@ -93,6 +106,18 @@ namespace Google.ProtocolBuffers {
       return (uint) (fieldNumber << TagTypeBits) | (uint) wireType;
     }
 
+    public static uint MakeTag(FieldDescriptor field) {
+      return MakeTag(field.FieldNumber, GetWireType(field));
+    }
+
+    /// <summary>
+    /// Returns the wire type for the given field descriptor. This differs
+    /// from GetWireType(FieldType) for packed repeated fields.
+    /// </summary>
+    internal static WireType GetWireType(FieldDescriptor descriptor) {
+      return descriptor.IsPacked ? WireType.LengthDelimited : GetWireType(descriptor.FieldType);
+    }
+
     /// <summary>
     /// Converts a field type to its wire type. Done with a switch for the sake
     /// of speed - this is significantly faster than a dictionary lookup.

二進制
testdata/golden_packed_fields_message


+ 7 - 3
todo.txt

@@ -1,10 +1,14 @@
 Current task list (not in order)
 
-- Performance framework
-- Optionally remove dependencies to core and csharp options (2.0.3
-  will remove core dependency)
+- Optionally remove dependencies to csharp options
 - Remove multifile support
 - Mono support
 - Docs
 - Clean up protogen code
 - Add flags to protogen
+- Avoid using reflection for messages which don't need it (is this
+  possible?)
+- Add RegisterAllExtensions
+- Add ToBuilder changes from Google's r92
+- Silverlight changes (as per email to Jon)
+

部分文件因文件數量過多而無法顯示