/// <summary>
        /// Reads a basic value from the stream.
        /// </summary>
        /// <param name="typeInfo">The type to be deserialized.</param>
        /// <param name="reader">The stream containing serialized data.</param>
        /// <param name="baseValue">The default value for this field.</param>
        /// <returns>The deserialized value.</returns>
        internal static object ReadValue(TypeInfo typeInfo, IReader reader, object baseValue)
        {
            object result = null;
            int    n;
            var    info = typeInfo.info & SerializationTypeInfo.VALUE_MASK;

            switch (info)
            {
            case SerializationTypeInfo.UserDefined:
                n = reader.ReadInt32();
                if (n >= 0)
                {
                    var itemType = typeInfo.type;
                    if (baseValue == null)
                    {
                        result = ConstructorDelegator.CreateInstance(itemType);
                    }
                    else
                    {
                        result = baseValue;
                    }
                    FastSerializationManager.GetFastDeserializationMapping(itemType).
                    Deserialize(result, reader);
                }
                break;

            case SerializationTypeInfo.SByte:
                result = reader.ReadSByte();
                break;

            case SerializationTypeInfo.Byte:
                result = reader.ReadByte();
                break;

            case SerializationTypeInfo.Boolean:
                result = reader.ReadByte() == 1;
                break;

            case SerializationTypeInfo.Int16:
                result = reader.ReadInt16();
                break;

            case SerializationTypeInfo.UInt16:
                result = reader.ReadUInt16();
                break;

            case SerializationTypeInfo.Int32:
                result = reader.ReadInt32();
                break;

            case SerializationTypeInfo.UInt32:
                result = reader.ReadUInt32();
                break;

            case SerializationTypeInfo.Int64:
                result = reader.ReadInt64();
                break;

            case SerializationTypeInfo.UInt64:
                result = reader.ReadUInt64();
                break;

            case SerializationTypeInfo.Single:
                result = reader.ReadSingle();
                break;

            case SerializationTypeInfo.Double:
                result = reader.ReadDouble();
                break;

            case SerializationTypeInfo.String:
                result = reader.ReadKleiString();
                break;

            case SerializationTypeInfo.Enumeration:
                result = Enum.ToObject(typeInfo.type, reader.ReadInt32());
                break;

            case SerializationTypeInfo.Vector2I:
                result = reader.ReadVector2I();
                break;

            case SerializationTypeInfo.Vector2:
                result = reader.ReadVector2();
                break;

            case SerializationTypeInfo.Vector3:
                result = reader.ReadVector3();
                break;

            case SerializationTypeInfo.Array:
                reader.ReadInt32();
                result = ReadArray(typeInfo, reader, true);
                break;

            case SerializationTypeInfo.Pair:
                n = reader.ReadInt32();
                if (n >= 0)
                {
                    TypeInfo keyType = typeInfo.subTypes[0], valueType = typeInfo.subTypes[1];
                    object   key   = ReadValue(keyType, reader, null);
                    object   value = ReadValue(valueType, reader, null);
                    result = KeyValuePairDelegator.GetDelegates(keyType.type, valueType.type).
                             CreateInstance(key, value);
                }
                break;

            case SerializationTypeInfo.Dictionary:
                reader.ReadInt32();
                n = reader.ReadInt32();
                if (n >= 0)
                {
                    // Preallocate dictionary to correct size
                    result = DictionaryDelegator.CreateInstance(typeInfo.
                                                                genericInstantiationType, n);
                    var dict      = result as System.Collections.IDictionary;
                    var keyType   = typeInfo.subTypes[0];
                    var valueType = typeInfo.subTypes[1];
                    var values    = ListPool <object, FastDeserializationMapping> .Allocate();

                    for (int i = 0; i < n; i++)
                    {
                        values.Add(ReadValue(valueType, reader, null));
                    }
                    for (int i = 0; i < n; i++)
                    {
                        dict.Add(ReadValue(keyType, reader, null), values[i]);
                    }
                    values.Recycle();
                }
                break;

            case SerializationTypeInfo.HashSet:
                reader.ReadInt32();
                result = ReadArray(typeInfo, reader, false);
                if (result != null)
                {
                    result = CollectionDelegator.CreateInstance(typeInfo.
                                                                genericInstantiationType, result);
                }
                break;

            case SerializationTypeInfo.List:
            case SerializationTypeInfo.Queue:
                reader.ReadInt32();
                result = ReadArray(typeInfo, reader, true);
                if (result != null)
                {
                    // Due to how POD lists/queues are encoded, must go through a temporary
                    // array to make best usage of ReadArrayFast, sorry memory usage
                    result = CollectionDelegator.CreateInstance(typeInfo.
                                                                genericInstantiationType, result);
                }
                break;

            case SerializationTypeInfo.Colour:
                result = reader.ReadColour();
                break;

            default:
                throw new ArgumentException("Unknown type " + info);
            }
            return(result);
        }
Example #2
0
        /// <summary>
        /// Serializes a value to the specified stream.
        /// </summary>
        /// <param name="writer">The stream where the data will be serialized.</param>
        /// <param name="typeInfo">The type to be serialized.</param>
        /// <param name="data">The data to serialize.</param>
        public static void WriteValue(BinaryWriter writer, TypeInfo typeInfo, object data)
        {
            switch (typeInfo.info & SerializationTypeInfo.VALUE_MASK)
            {
            case SerializationTypeInfo.UserDefined:
                if (data != null)
                {
                    long startPos = writer.BaseStream.Position;
                    writer.Write(0);
                    long basePos = writer.BaseStream.Position;
                    GetFastSerializationTemplate(typeInfo.type).SerializeData(data, writer);
                    WriteLength(writer, startPos, basePos);
                }
                else
                {
                    writer.Write(-1);
                }
                break;

            case SerializationTypeInfo.SByte:
                writer.Write((sbyte)data);
                break;

            case SerializationTypeInfo.Byte:
                writer.Write((byte)data);
                break;

            case SerializationTypeInfo.Boolean:
                writer.Write((byte)((data is bool which && which) ? 1 : 0));
                break;

            case SerializationTypeInfo.Int16:
                writer.Write((short)data);
                break;

            case SerializationTypeInfo.UInt16:
                writer.Write((ushort)data);
                break;

            case SerializationTypeInfo.Int32:
                writer.Write((int)data);
                break;

            case SerializationTypeInfo.UInt32:
                writer.Write((uint)data);
                break;

            case SerializationTypeInfo.Int64:
                writer.Write((long)data);
                break;

            case SerializationTypeInfo.UInt64:
                writer.Write((ulong)data);
                break;

            case SerializationTypeInfo.Single:
                writer.WriteSingleFast((float)data);
                break;

            case SerializationTypeInfo.Double:
                writer.Write((double)data);
                break;

            case SerializationTypeInfo.String:
                writer.WriteKleiString((string)data);
                break;

            case SerializationTypeInfo.Enumeration:
                writer.Write((int)data);
                break;

            case SerializationTypeInfo.Vector2I:
                if (data is Vector2I vector2i)
                {
                    writer.Write(vector2i.x);
                    writer.Write(vector2i.y);
                }
                else
                {
                    writer.Write(0);
                    writer.Write(0);
                }
                break;

            case SerializationTypeInfo.Vector2:
                if (data is Vector2 vector2)
                {
                    writer.WriteSingleFast(vector2.x);
                    writer.WriteSingleFast(vector2.y);
                }
                else
                {
                    writer.WriteSingleFast(0.0f);
                    writer.WriteSingleFast(0.0f);
                }
                break;

            case SerializationTypeInfo.Vector3:
                if (data is Vector3 vector3)
                {
                    writer.WriteSingleFast(vector3.x);
                    writer.WriteSingleFast(vector3.y);
                    writer.WriteSingleFast(vector3.z);
                }
                else
                {
                    for (int i = 0; i < 3; i++)
                    {
                        writer.WriteSingleFast(0.0f);
                    }
                }
                break;

            case SerializationTypeInfo.Array:
                if (data is Array array)
                {
                    var  elementType = typeInfo.subTypes[0];
                    int  n           = array.Length;
                    long startPos    = writer.BaseStream.Position;
                    writer.Write(0);
                    writer.Write(n);
                    long basePos = writer.BaseStream.Position;
                    if (Helper.IsPOD(elementType.info))
                    {
                        WriteArrayPOD(writer, elementType, array);
                    }
                    else if (Helper.IsValueType(elementType.info))
                    {
                        var template = GetFastSerializationTemplate(elementType.type);
                        for (int i = 0; i < n; i++)
                        {
                            template.SerializeData(array.GetValue(i), writer);
                        }
                    }
                    else
                    {
                        for (int i = 0; i < n; i++)
                        {
                            WriteValue(writer, elementType, array.GetValue(i));
                        }
                    }
                    WriteLength(writer, startPos, basePos);
                }
                else
                {
                    writer.Write(0);
                    writer.Write(-1);
                }
                break;

            case SerializationTypeInfo.Pair:
                if (data != null)
                {
                    TypeInfo keyType = typeInfo.subTypes[0], valueType = typeInfo.subTypes[1];
                    var      delegator = KeyValuePairDelegator.GetDelegates(keyType.type,
                                                                            valueType.type);
                    long startPos = writer.BaseStream.Position;
                    writer.Write(0);
                    long basePos = writer.BaseStream.Position;
                    WriteValue(writer, keyType, delegator.GetKey(data));
                    WriteValue(writer, valueType, delegator.GetValue(data));
                    WriteLength(writer, startPos, basePos);
                }
                else
                {
                    writer.Write(4);
                    writer.Write(-1);
                }
                break;

            case SerializationTypeInfo.Dictionary:
                if (data is IDictionary dict)
                {
                    TypeInfo keyType = typeInfo.subTypes[0], valueType = typeInfo.subTypes[1];
                    long     startPos = writer.BaseStream.Position;
                    writer.Write(0);
                    writer.Write(dict.Count);
                    long basePos = writer.BaseStream.Position;
                    foreach (object value in dict.Values)
                    {
                        WriteValue(writer, valueType, value);
                    }
                    foreach (object key in dict.Keys)
                    {
                        WriteValue(writer, keyType, key);
                    }
                    WriteLength(writer, startPos, basePos);
                }
                else
                {
                    writer.Write(0);
                    writer.Write(-1);
                }
                break;

            case SerializationTypeInfo.List:
            case SerializationTypeInfo.Queue:
                if (data is ICollection list)
                {
                    var  elementType = typeInfo.subTypes[0];
                    long startPos    = writer.BaseStream.Position;
                    writer.Write(0);
                    writer.Write(list.Count);
                    long basePos = writer.BaseStream.Position;
                    if (Helper.IsPOD(elementType.info))
                    {
                        WriteListPOD(writer, elementType, list);
                    }
                    else if (Helper.IsValueType(elementType.info))
                    {
                        var template = GetFastSerializationTemplate(elementType.type);
                        foreach (object element in list)
                        {
                            template.SerializeData(element, writer);
                        }
                    }
                    else
                    {
                        foreach (object element in list)
                        {
                            WriteValue(writer, elementType, element);
                        }
                    }
                    WriteLength(writer, startPos, basePos);
                }
                else
                {
                    writer.Write(0);
                    writer.Write(-1);
                }
                break;

            case SerializationTypeInfo.HashSet:
                if (data is IEnumerable enumerable)
                {
                    var  elementType = typeInfo.subTypes[0];
                    long startPos    = writer.BaseStream.Position;
                    writer.Write(0);
                    writer.Write(0);
                    long basePos = writer.BaseStream.Position;
                    int  n       = 0;
                    // No special case handling for POD for hash sets
                    if (Helper.IsValueType(elementType.info))
                    {
                        var template = GetFastSerializationTemplate(elementType.type);
                        foreach (object element in enumerable)
                        {
                            template.SerializeData(element, writer);
                            n++;
                        }
                    }
                    else
                    {
                        foreach (object element in enumerable)
                        {
                            WriteValue(writer, elementType, element);
                            n++;
                        }
                    }
                    // Element count must be written along with the length
                    long endPos = writer.BaseStream.Position;
                    writer.BaseStream.Position = startPos;
                    writer.Write((int)(endPos - basePos));
                    writer.Write(n);
                    writer.BaseStream.Position = endPos;
                }
                else
                {
                    writer.Write(0);
                    writer.Write(-1);
                }
                break;

            case SerializationTypeInfo.Colour:
                if (data is Color color)
                {
                    writer.Write((byte)(color.r * 255f));
                    writer.Write((byte)(color.g * 255f));
                    writer.Write((byte)(color.b * 255f));
                    writer.Write((byte)(color.a * 255f));
                }
                else
                {
                    for (int i = 0; i < 4; i++)
                    {
                        writer.Write((byte)0);
                    }
                }
                break;

            default:
                throw new ArgumentException("Unable to serialize type: " + typeInfo.type.
                                            FullName);
            }
        }