Split off the Serialization namespace into a new assembly.
diff --git a/src/ProtocolBuffers.Serialization/AbstractReader.cs b/src/ProtocolBuffers.Serialization/AbstractReader.cs
new file mode 100644
index 0000000..f54c270
--- /dev/null
+++ b/src/ProtocolBuffers.Serialization/AbstractReader.cs
@@ -0,0 +1,697 @@
+using System;

+using System.Collections.Generic;

+using Google.ProtocolBuffers.Descriptors;

+

+//Disable CS3011: only CLS-compliant members can be abstract

+#pragma warning disable 3011

+

+namespace Google.ProtocolBuffers.Serialization

+{

+    /// <summary>

+    /// Provides a base-class that provides some basic functionality for handling type dispatching

+    /// </summary>

+    public abstract class AbstractReader : ICodedInputStream

+    {

+        private const int DefaultMaxDepth = 64;

+        private int _depth;

+        

+        /// <summary> Constructs a new reader </summary>

+        protected AbstractReader() { MaxDepth = DefaultMaxDepth; }

+        /// <summary> Constructs a new child reader </summary>

+        protected AbstractReader(AbstractReader copyFrom)

+        {

+            _depth = copyFrom._depth + 1;

+            MaxDepth = copyFrom.MaxDepth;

+        }

+

+        /// <summary> Gets or sets the maximum recursion depth allowed </summary>

+        public int MaxDepth { get; set; }

+

+        /// <summary>

+        /// Merges the contents of stream into the provided message builder

+        /// </summary>

+        public TBuilder Merge<TBuilder>(TBuilder builder) where TBuilder : IBuilderLite

+        {

+            return Merge(builder, ExtensionRegistry.Empty);

+        }

+

+        /// <summary>

+        /// Merges the contents of stream into the provided message builder

+        /// </summary>

+        public abstract TBuilder Merge<TBuilder>(TBuilder builder, ExtensionRegistry registry)

+            where TBuilder : IBuilderLite;

+

+        /// <summary>

+        /// Peeks at the next field in the input stream and returns what information is available.

+        /// </summary>

+        /// <remarks>

+        /// This may be called multiple times without actually reading the field.  Only after the field

+        /// is either read, or skipped, should PeekNext return a different value.

+        /// </remarks>

+        protected abstract bool PeekNext(out string field);

+

+        /// <summary>

+        /// Causes the reader to skip past this field

+        /// </summary>

+        protected abstract void Skip();

+

+        /// <summary>

+        /// Returns true if it was able to read a Boolean from the input

+        /// </summary>

+        protected abstract bool Read(ref bool value);

+

+        /// <summary>

+        /// Returns true if it was able to read a Int32 from the input

+        /// </summary>

+        protected abstract bool Read(ref int value);

+

+        /// <summary>

+        /// Returns true if it was able to read a UInt32 from the input

+        /// </summary>

+        [CLSCompliant(false)]

+        protected abstract bool Read(ref uint value);

+

+        /// <summary>

+        /// Returns true if it was able to read a Int64 from the input

+        /// </summary>

+        protected abstract bool Read(ref long value);

+

+        /// <summary>

+        /// Returns true if it was able to read a UInt64 from the input

+        /// </summary>

+        [CLSCompliant(false)]

+        protected abstract bool Read(ref ulong value);

+

+        /// <summary>

+        /// Returns true if it was able to read a Single from the input

+        /// </summary>

+        protected abstract bool Read(ref float value);

+

+        /// <summary>

+        /// Returns true if it was able to read a Double from the input

+        /// </summary>

+        protected abstract bool Read(ref double value);

+

+        /// <summary>

+        /// Returns true if it was able to read a String from the input

+        /// </summary>

+        protected abstract bool Read(ref string value);

+

+        /// <summary>

+        /// Returns true if it was able to read a ByteString from the input

+        /// </summary>

+        protected abstract bool Read(ref ByteString value);

+

+        /// <summary>

+        /// returns true if it was able to read a single value into the value reference.  The value

+        /// stored may be of type System.String, System.Int32, or an IEnumLite from the IEnumLiteMap.

+        /// </summary>

+        protected abstract bool ReadEnum(ref object value);

+

+        /// <summary>

+        /// Merges the input stream into the provided IBuilderLite 

+        /// </summary>

+        protected abstract bool ReadMessage(IBuilderLite builder, ExtensionRegistry registry);

+

+        /// <summary>

+        /// Merges the input stream into the provided IBuilderLite 

+        /// </summary>

+        public virtual bool ReadGroup(IBuilderLite value, ExtensionRegistry registry)

+        {

+            return ReadMessage(value, registry);

+        }

+

+        /// <summary>

+        /// Cursors through the array elements and stops at the end of the array

+        /// </summary>

+        protected virtual IEnumerable<string> ForeachArrayItem(string field)

+        {

+            string next = field;

+            while (true)

+            {

+                yield return next;

+

+                if (!PeekNext(out next) || next != field)

+                {

+                    break;

+                }

+            }

+        }

+

+        /// <summary>

+        /// Reads an array of T messages

+        /// </summary>

+        public virtual bool ReadMessageArray<T>(string field, ICollection<T> items, IMessageLite messageType,

+                                                ExtensionRegistry registry)

+        {

+            bool success = false;

+            foreach (string next in ForeachArrayItem(field))

+            {

+                IBuilderLite builder = messageType.WeakCreateBuilderForType();

+                if (ReadMessage(builder, registry))

+                {

+                    items.Add((T) builder.WeakBuild());

+                    success |= true;

+                }

+            }

+            return success;

+        }

+

+        /// <summary>

+        /// Reads an array of T messages as a proto-buffer group

+        /// </summary>

+        public virtual bool ReadGroupArray<T>(string field, ICollection<T> items, IMessageLite messageType,

+                                              ExtensionRegistry registry)

+        {

+            bool success = false;

+            foreach (string next in ForeachArrayItem(field))

+            {

+                IBuilderLite builder = messageType.WeakCreateBuilderForType();

+                if (ReadGroup(builder, registry))

+                {

+                    items.Add((T) builder.WeakBuild());

+                    success |= true;

+                }

+            }

+            return success;

+        }

+

+        /// <summary>

+        /// Reads an array of System.Enum type T and adds them to the collection

+        /// </summary>

+        public virtual bool ReadEnumArray(string field, ICollection<object> items)

+        {

+            bool success = false;

+            foreach (string next in ForeachArrayItem(field))

+            {

+                object temp = null;

+                if (ReadEnum(ref temp))

+                {

+                    items.Add(temp);

+                    success |= true;

+                }

+            }

+            return success;

+        }

+

+        /// <summary>

+        /// Reads an array of T, where T is a primitive type defined by FieldType

+        /// </summary>

+        public virtual bool ReadArray<T>(FieldType type, string field, ICollection<T> items)

+        {

+            bool success = false;

+            foreach (string next in ForeachArrayItem(field))

+            {

+                object temp = null;

+                if (ReadField(type, ref temp))

+                {

+                    items.Add((T) temp);

+                    success |= true;

+                }

+            }

+            return success;

+        }

+

+        /// <summary>

+        /// returns true if it was able to read a single primitive value of FieldType into the value reference

+        /// </summary>

+        public virtual bool ReadField(FieldType type, ref object value)

+        {

+            switch (type)

+            {

+                case FieldType.Bool:

+                    {

+                        bool temp = false;

+                        if (Read(ref temp))

+                        {

+                            value = temp;

+                        }

+                        else

+                        {

+                            return false;

+                        }

+                        break;

+                    }

+                case FieldType.Int64:

+                case FieldType.SInt64:

+                case FieldType.SFixed64:

+                    {

+                        long temp = 0;

+                        if (Read(ref temp))

+                        {

+                            value = temp;

+                        }

+                        else

+                        {

+                            return false;

+                        }

+                        break;

+                    }

+                case FieldType.UInt64:

+                case FieldType.Fixed64:

+                    {

+                        ulong temp = 0;

+                        if (Read(ref temp))

+                        {

+                            value = temp;

+                        }

+                        else

+                        {

+                            return false;

+                        }

+                        break;

+                    }

+                case FieldType.Int32:

+                case FieldType.SInt32:

+                case FieldType.SFixed32:

+                    {

+                        int temp = 0;

+                        if (Read(ref temp))

+                        {

+                            value = temp;

+                        }

+                        else

+                        {

+                            return false;

+                        }

+                        break;

+                    }

+                case FieldType.UInt32:

+                case FieldType.Fixed32:

+                    {

+                        uint temp = 0;

+                        if (Read(ref temp))

+                        {

+                            value = temp;

+                        }

+                        else

+                        {

+                            return false;

+                        }

+                        break;

+                    }

+                case FieldType.Float:

+                    {

+                        float temp = float.NaN;

+                        if (Read(ref temp))

+                        {

+                            value = temp;

+                        }

+                        else

+                        {

+                            return false;

+                        }

+                        break;

+                    }

+                case FieldType.Double:

+                    {

+                        double temp = float.NaN;

+                        if (Read(ref temp))

+                        {

+                            value = temp;

+                        }

+                        else

+                        {

+                            return false;

+                        }

+                        break;

+                    }

+                case FieldType.String:

+                    {

+                        string temp = null;

+                        if (Read(ref temp))

+                        {

+                            value = temp;

+                        }

+                        else

+                        {

+                            return false;

+                        }

+                        break;

+                    }

+                case FieldType.Bytes:

+                    {

+                        ByteString temp = null;

+                        if (Read(ref temp))

+                        {

+                            value = temp;

+                        }

+                        else

+                        {

+                            return false;

+                        }

+                        break;

+                    }

+                default:

+                    throw InvalidProtocolBufferException.InvalidTag();

+            }

+            return true;

+        }

+

+        #region ICodedInputStream Members

+

+        bool ICodedInputStream.ReadTag(out uint fieldTag, out string fieldName)

+        {

+            fieldTag = 0;

+            if (PeekNext(out fieldName))

+            {

+                return true;

+            }

+            return false;

+        }

+

+        bool ICodedInputStream.ReadDouble(ref double value)

+        {

+            return Read(ref value);

+        }

+

+        bool ICodedInputStream.ReadFloat(ref float value)

+        {

+            return Read(ref value);

+        }

+

+        bool ICodedInputStream.ReadUInt64(ref ulong value)

+        {

+            return Read(ref value);

+        }

+

+        bool ICodedInputStream.ReadInt64(ref long value)

+        {

+            return Read(ref value);

+        }

+

+        bool ICodedInputStream.ReadInt32(ref int value)

+        {

+            return Read(ref value);

+        }

+

+        bool ICodedInputStream.ReadFixed64(ref ulong value)

+        {

+            return Read(ref value);

+        }

+

+        bool ICodedInputStream.ReadFixed32(ref uint value)

+        {

+            return Read(ref value);

+        }

+

+        bool ICodedInputStream.ReadBool(ref bool value)

+        {

+            return Read(ref value);

+        }

+

+        bool ICodedInputStream.ReadString(ref string value)

+        {

+            return Read(ref value);

+        }

+

+        void ICodedInputStream.ReadGroup(int fieldNumber, IBuilderLite builder, ExtensionRegistry extensionRegistry)

+        {

+            if (_depth++ > MaxDepth)

+            {

+                throw new RecursionLimitExceededException();

+            }

+            ReadGroup(builder, extensionRegistry);

+            _depth--;

+        }

+

+        void ICodedInputStream.ReadUnknownGroup(int fieldNumber, IBuilderLite builder)

+        {

+            throw new NotSupportedException();

+        }

+

+        void ICodedInputStream.ReadMessage(IBuilderLite builder, ExtensionRegistry extensionRegistry)

+        {

+            if (_depth++ > MaxDepth)

+            {

+                throw new RecursionLimitExceededException();

+            }

+            ReadMessage(builder, extensionRegistry);

+            _depth--;

+        }

+

+        bool ICodedInputStream.ReadBytes(ref ByteString value)

+        {

+            return Read(ref value);

+        }

+

+        bool ICodedInputStream.ReadUInt32(ref uint value)

+        {

+            return Read(ref value);

+        }

+

+        bool ICodedInputStream.ReadEnum(ref IEnumLite value, out object unknown, IEnumLiteMap mapping)

+        {

+            value = null;

+            unknown = null;

+            if (ReadEnum(ref unknown))

+            {

+                if (unknown is int)

+                {

+                    value = mapping.FindValueByNumber((int) unknown);

+                }

+                else if (unknown is string)

+                {

+                    value = mapping.FindValueByName((string) unknown);

+                }

+                return value != null;

+            }

+            return false;

+        }

+

+        bool ICodedInputStream.ReadEnum<T>(ref T value, out object rawValue)

+        {

+            rawValue = null;

+            if (ReadEnum(ref rawValue))

+            {

+                if (Enum.IsDefined(typeof (T), rawValue))

+                {

+                    if (rawValue is int)

+                    {

+                        value = (T) rawValue;

+                    }

+                    else if (rawValue is string)

+                    {

+                        value = (T) Enum.Parse(typeof (T), (string) rawValue, false);

+                    }

+                    else

+                    {

+                        value = default(T);

+                        return false;

+                    }

+                    return true;

+                }

+            }

+            return false;

+        }

+

+        bool ICodedInputStream.ReadSFixed32(ref int value)

+        {

+            return Read(ref value);

+        }

+

+        bool ICodedInputStream.ReadSFixed64(ref long value)

+        {

+            return Read(ref value);

+        }

+

+        bool ICodedInputStream.ReadSInt32(ref int value)

+        {

+            return Read(ref value);

+        }

+

+        bool ICodedInputStream.ReadSInt64(ref long value)

+        {

+            return Read(ref value);

+        }

+

+        void ICodedInputStream.ReadPrimitiveArray(FieldType fieldType, uint fieldTag, string fieldName,

+                                                  ICollection<object> list)

+        {

+            ReadArray(fieldType, fieldName, list);

+        }

+

+        void ICodedInputStream.ReadEnumArray(uint fieldTag, string fieldName, ICollection<IEnumLite> list,

+                                             out ICollection<object> unknown, IEnumLiteMap mapping)

+        {

+            unknown = null;

+            List<object> array = new List<object>();

+            if (ReadEnumArray(fieldName, array))

+            {

+                foreach (object rawValue in array)

+                {

+                    IEnumLite item = null;

+                    if (rawValue is int)

+                    {

+                        item = mapping.FindValueByNumber((int) rawValue);

+                    }

+                    else if (rawValue is string)

+                    {

+                        item = mapping.FindValueByName((string) rawValue);

+                    }

+

+                    if (item != null)

+                    {

+                        list.Add(item);

+                    }

+                    else

+                    {

+                        if (unknown == null)

+                        {

+                            unknown = new List<object>();

+                        }

+                        unknown.Add(rawValue);

+                    }

+                }

+            }

+        }

+

+        void ICodedInputStream.ReadEnumArray<T>(uint fieldTag, string fieldName, ICollection<T> list,

+                                                out ICollection<object> unknown)

+        {

+            unknown = null;

+            List<object> array = new List<object>();

+            if (ReadEnumArray(fieldName, array))

+            {

+                foreach (object rawValue in array)

+                {

+                    if (rawValue is int)

+                    {

+                        list.Add((T) rawValue);

+                    }

+                    else if (rawValue is string)

+                    {

+                        list.Add((T) Enum.Parse(typeof (T), (string) rawValue, false));

+                    }

+                    else

+                    {

+                        if (unknown == null)

+                        {

+                            unknown = new List<object>();

+                        }

+                        unknown.Add(rawValue);

+                    }

+                }

+            }

+        }

+

+        void ICodedInputStream.ReadMessageArray<T>(uint fieldTag, string fieldName, ICollection<T> list, T messageType,

+                                                   ExtensionRegistry registry)

+        {

+            if (_depth++ > MaxDepth)

+            {

+                throw new RecursionLimitExceededException();

+            }

+            ReadMessageArray(fieldName, list, messageType, registry);

+            _depth--;

+        }

+

+        void ICodedInputStream.ReadGroupArray<T>(uint fieldTag, string fieldName, ICollection<T> list, T messageType,

+                                                 ExtensionRegistry registry)

+        {

+            if (_depth++ > MaxDepth)

+            {

+                throw new RecursionLimitExceededException();

+            }

+            ReadGroupArray(fieldName, list, messageType, registry);

+            _depth--;

+        }

+

+        bool ICodedInputStream.ReadPrimitiveField(FieldType fieldType, ref object value)

+        {

+            return ReadField(fieldType, ref value);

+        }

+

+        bool ICodedInputStream.IsAtEnd

+        {

+            get

+            {

+                string next;

+                return PeekNext(out next) == false;

+            }

+        }

+

+        bool ICodedInputStream.SkipField()

+        {

+            Skip();

+            return true;

+        }

+

+        void ICodedInputStream.ReadStringArray(uint fieldTag, string fieldName, ICollection<string> list)

+        {

+            ReadArray(FieldType.String, fieldName, list);

+        }

+

+        void ICodedInputStream.ReadBytesArray(uint fieldTag, string fieldName, ICollection<ByteString> list)

+        {

+            ReadArray(FieldType.Bytes, fieldName, list);

+        }

+

+        void ICodedInputStream.ReadBoolArray(uint fieldTag, string fieldName, ICollection<bool> list)

+        {

+            ReadArray(FieldType.Bool, fieldName, list);

+        }

+

+        void ICodedInputStream.ReadInt32Array(uint fieldTag, string fieldName, ICollection<int> list)

+        {

+            ReadArray(FieldType.Int32, fieldName, list);

+        }

+

+        void ICodedInputStream.ReadSInt32Array(uint fieldTag, string fieldName, ICollection<int> list)

+        {

+            ReadArray(FieldType.SInt32, fieldName, list);

+        }

+

+        void ICodedInputStream.ReadUInt32Array(uint fieldTag, string fieldName, ICollection<uint> list)

+        {

+            ReadArray(FieldType.UInt32, fieldName, list);

+        }

+

+        void ICodedInputStream.ReadFixed32Array(uint fieldTag, string fieldName, ICollection<uint> list)

+        {

+            ReadArray(FieldType.Fixed32, fieldName, list);

+        }

+

+        void ICodedInputStream.ReadSFixed32Array(uint fieldTag, string fieldName, ICollection<int> list)

+        {

+            ReadArray(FieldType.SFixed32, fieldName, list);

+        }

+

+        void ICodedInputStream.ReadInt64Array(uint fieldTag, string fieldName, ICollection<long> list)

+        {

+            ReadArray(FieldType.Int64, fieldName, list);

+        }

+

+        void ICodedInputStream.ReadSInt64Array(uint fieldTag, string fieldName, ICollection<long> list)

+        {

+            ReadArray(FieldType.SInt64, fieldName, list);

+        }

+

+        void ICodedInputStream.ReadUInt64Array(uint fieldTag, string fieldName, ICollection<ulong> list)

+        {

+            ReadArray(FieldType.UInt64, fieldName, list);

+        }

+

+        void ICodedInputStream.ReadFixed64Array(uint fieldTag, string fieldName, ICollection<ulong> list)

+        {

+            ReadArray(FieldType.Fixed64, fieldName, list);

+        }

+

+        void ICodedInputStream.ReadSFixed64Array(uint fieldTag, string fieldName, ICollection<long> list)

+        {

+            ReadArray(FieldType.SFixed64, fieldName, list);

+        }

+

+        void ICodedInputStream.ReadDoubleArray(uint fieldTag, string fieldName, ICollection<double> list)

+        {

+            ReadArray(FieldType.Double, fieldName, list);

+        }

+

+        void ICodedInputStream.ReadFloatArray(uint fieldTag, string fieldName, ICollection<float> list)

+        {

+            ReadArray(FieldType.Float, fieldName, list);

+        }

+

+        #endregion

+    }

+}
\ No newline at end of file