Example #1
0
        /// <summary>
        /// Serializes an <paramref name="obj"/> of type <paramref name="type"/> into <paramref name="buffer"/>
        /// </summary>
        /// <param name="buffer">The buffer to serialize the object into</param>
        /// <param name="obj">The object to serialize</param>
        /// <param name="type">The object's type, or null to get it from <paramref name="obj"/></param>
        public void Serialize(TBuffer buffer, object obj, Type type = null)
        {
            type = type ?? obj?.GetType() ?? throw new ArgumentNullException("obj is null and no type has been specified");

            if (!Serializers.TryGetValue(type, out var ser))
            {
                var bufferParam = Parameter(typeof(TBuffer), "_buffer");
                var objParam    = Parameter(typeof(object), "_obj");
                var exprs       = new List <Expression>();

                if (Options.WriteHeader)
                {
                    //Write 243, or 244 if Options.WriteStructureSignature is on
                    exprs.Add(Formats.Get(typeof(byte)).Serialize(new FormatContextWithValue(Formats, typeof(byte), bufferParam, Constant((byte)(Options.WriteStructureSignature ? MagicWithSignature : Magic)))));

                    if (Options.WriteStructureSignature)
                    {
                        var hash = ClassSignature.Get(type);
                        exprs.Add(Formats.Get(typeof(string)).Serialize(new FormatContextWithValue(Formats, typeof(string), bufferParam, Constant(hash))));
                    }
                }

                exprs.AddRange(GetBlock(objParam, bufferParam, type));

                Serializers[type] = ser = Lambda <Action <TBuffer, object> >(Block(exprs), bufferParam, objParam).Compile();
            }

            ser(buffer, obj);

            IEnumerable <Expression> GetBlock(Expression objExpr, Expression bufferExpr, Type objType)
            {
                var convertedObj = Convert(objExpr, objType);

                foreach (var field in GetFields(objType))
                {
                    var format = Formats.Get(field.MemberType);

                    if (format == null)
                    {
                        if (Options.SerializeUnknownTypes)
                        {
                            yield return(Block(GetBlock(PropertyOrField(convertedObj, field.Name), bufferExpr, field.MemberType)));
                        }
                        else
                        {
                            throw new Exception($"Format not found for '{type.Name}.{field.Name}'");
                        }
                    }
                    else
                    {
                        yield return(format.Serialize(new FormatContextWithValue(
                                                          Formats, field.MemberType, bufferExpr, PropertyOrField(convertedObj, field.Name), field.GetConcreteType())));
                    }
                }
            }
        }
Example #2
0
        /// <summary>
        /// Reads an object of type <paramref name="type"/> from <paramref name="buffer"/>.
        /// </summary>
        /// <param name="buffer">The buffer to read from</param>
        /// <param name="type">The type of the object to read</param>
        public object Deserialize(TBuffer buffer, Type type)
        {
            if (!Deserializers.TryGetValue(type, out var des))
            {
                var exprs       = new List <Expression>();
                var bufferParam = Parameter(typeof(TBuffer), "_buffer");
                var objVar      = Variable(typeof(object), "_obj");

                if (Options.CheckHeader)
                {
                    var magicVar = Variable(typeof(byte), "_magic");
                    var hash     = ClassSignature.Get(type);

                    /*
                     * byte magic = Read<byte>();
                     * if (magic == 244)
                     * {
                     *   if (Read<string>() != "HASH")
                     *   {
                     *       if (Options.CheckStructureSignature)
                     *           throw new Exception();
                     *   }
                     * }
                     * else if (magic != 243)
                     * {
                     *   throw new Exception();
                     * }
                     */
                    exprs.Add(Block(new[] { magicVar },
                                    Assign(magicVar, Read <byte>()),
                                    IfThenElse(
                                        Equal(magicVar, Constant(MagicWithSignature)),
                                        IfThen(NotEqual(Read <string>(), Constant(hash)), Options.CheckStructureSignature ? InvalidHeaderException.Throw("Class structure signature mismatch") : Block()),
                                        IfThen(NotEqual(magicVar, Constant(Magic)), InvalidHeaderException.Throw("Invalid magic number")))));
                }

                exprs.AddRange(GetBlock(objVar, bufferParam, type));
                exprs.Add(objVar);

                Deserializers[type] = des = Lambda <Func <TBuffer, object> >(Block(new[] { objVar }, exprs), bufferParam).Compile();

                Expression Read <T>() => Formats.Get(typeof(T))?.Deserialize(new FormatContext(Formats, typeof(T), bufferParam)) ?? throw new InvalidOperationException("Cannot deserialize type " + typeof(T).FullName);
            }

            return(des(buffer));

            IEnumerable <Expression> GetBlock(Expression objExpr, Expression bufferExpr, Type objType)
            {
                var convertedObj = Convert(objExpr, objType);

                yield return(Assign(objExpr, New(objType)));

                foreach (var field in GetFields(objType))
                {
                    if (field.MemberType.IsInterface)
                    {
                        if (!field.Member.IsDefined(typeof(ConcreteTypeAttribute)))
                        {
                            throw new Exception("Fields of interface types must be decorated with ConcreteTypeAttribute");
                        }
                        else if (!field.MemberType.IsAssignableFrom(field.GetConcreteType()))
                        {
                            throw new Exception($"The specified concrete type for field '{field.Name}' doesn't implement the field type ({field.MemberType.Name})");
                        }
                    }

                    var format = Formats.Get(field.MemberType);

                    if (format == null)
                    {
                        if (Options.SerializeUnknownTypes)
                        {
                            yield return(Block(GetBlock(PropertyOrField(convertedObj, field.Name), bufferExpr, field.MemberType)));
                        }
                        else
                        {
                            throw new Exception($"Format not found for '{objType.Name}.{field.Name}'");
                        }
                    }
                    else
                    {
                        yield return(Assign(PropertyOrField(convertedObj, field.Name), format.Deserialize(
                                                new FormatContext(Formats, field.MemberType, bufferExpr, field.GetConcreteType()))));
                    }
                }
            }
        }