public void Serialise(ILGenerator ilg, LocalBuilder value, LocalBuilder packer, DasherContext context)
        {
            var type = value.LocalType;

            // treat as complex object and recur
            var props = type
                        .GetProperties(BindingFlags.Instance | BindingFlags.Public)
                        .Where(p => p.CanRead)
                        .ToList();

            // write map header
            ilg.Emit(OpCodes.Ldloc, packer);
            ilg.Emit(OpCodes.Ldc_I4, props.Count);
            ilg.Emit(OpCodes.Call, typeof(UnsafePacker).GetMethod(nameof(UnsafePacker.PackMapHeader)));

            // write each property's value
            foreach (var prop in props)
            {
                var propValue = ilg.DeclareLocal(prop.PropertyType);

                // write property name
                ilg.Emit(OpCodes.Ldloc, packer);
                ilg.Emit(OpCodes.Ldstr, prop.Name);
                ilg.Emit(OpCodes.Call, typeof(UnsafePacker).GetMethod(nameof(UnsafePacker.Pack), new[] { typeof(string) }));

                // get property value
                ilg.Emit(type.IsValueType ? OpCodes.Ldloca : OpCodes.Ldloc, value);
                ilg.Emit(OpCodes.Call, prop.GetMethod);
                ilg.Emit(OpCodes.Stloc, propValue);

                // find the property type's provider
                ITypeProvider provider;
                if (!context.TryGetTypeProvider(prop.PropertyType, out provider))
                {
                    throw new Exception($"Unable to serialise type {prop.PropertyType}");
                }

                // write property value
                provider.Serialise(ilg, propValue, packer, context);
            }
        }
示例#2
0
        public void Deserialise(ILGenerator ilg, string name, Type targetType, LocalBuilder value, LocalBuilder unpacker, LocalBuilder contextLocal, DasherContext context, UnexpectedFieldBehaviour unexpectedFieldBehaviour)
        {
            var nullableType = value.LocalType;
            var valueType    = nullableType.GetGenericArguments().Single();

            ITypeProvider valueProvider;

            if (!context.TryGetTypeProvider(valueType, out valueProvider))
            {
                throw new Exception($"Unable to deserialise values of type Nullable<{valueType}> from MsgPack data.");
            }

            var lblNull = ilg.DefineLabel();
            var lblExit = ilg.DefineLabel();

            ilg.Emit(OpCodes.Ldloc, unpacker);
            ilg.Emit(OpCodes.Call, typeof(Unpacker).GetMethod(nameof(Unpacker.TryReadNull)));

            ilg.Emit(OpCodes.Brtrue, lblNull);

            // non-null
            var nonNullValue = ilg.DeclareLocal(valueType);

            valueProvider.Deserialise(ilg, name, targetType, nonNullValue, unpacker, contextLocal, context, unexpectedFieldBehaviour);
            ilg.Emit(OpCodes.Ldloca, value);
            ilg.Emit(OpCodes.Ldloc, nonNullValue);
            ilg.Emit(OpCodes.Call, nullableType.GetConstructor(new [] { valueType }));

            ilg.Emit(OpCodes.Br, lblExit);
            ilg.MarkLabel(lblNull);

            // null
            ilg.Emit(OpCodes.Ldloca, value);
            ilg.Emit(OpCodes.Initobj, nullableType);

            ilg.MarkLabel(lblExit);
        }
示例#3
0
        public void Serialise(ILGenerator ilg, LocalBuilder value, LocalBuilder packer, DasherContext context)
        {
            var type      = value.LocalType;
            var valueType = type.GetGenericArguments().Single();

            ilg.Emit(OpCodes.Ldloca, value);
            ilg.Emit(OpCodes.Call, type.GetProperty(nameof(Nullable <int> .HasValue)).GetMethod);

            var lblNull = ilg.DefineLabel();
            var lblExit = ilg.DefineLabel();

            ilg.Emit(OpCodes.Brfalse, lblNull);

            // has a value to serialise
            ITypeProvider provider;

            if (!context.TryGetTypeProvider(valueType, out provider))
            {
                throw new Exception($"Cannot serialise underlying type of Nullable<{valueType}>");
            }
            var nonNullValue = ilg.DeclareLocal(valueType);

            ilg.Emit(OpCodes.Ldloca, value);
            ilg.Emit(OpCodes.Call, type.GetProperty(nameof(Nullable <int> .Value)).GetMethod);
            ilg.Emit(OpCodes.Stloc, nonNullValue);
            provider.Serialise(ilg, nonNullValue, packer, context);

            ilg.Emit(OpCodes.Br, lblExit);

            ilg.MarkLabel(lblNull);

            // value is null
            ilg.Emit(OpCodes.Ldloc, packer);
            ilg.Emit(OpCodes.Call, typeof(UnsafePacker).GetMethod(nameof(UnsafePacker.PackNull)));

            ilg.MarkLabel(lblExit);
        }
示例#4
0
        public void Deserialise(ILGenerator ilg, string name, Type targetType, LocalBuilder value, LocalBuilder unpacker, LocalBuilder contextLocal, DasherContext context, UnexpectedFieldBehaviour unexpectedFieldBehaviour)
        {
            var elementType = value.LocalType.GetGenericArguments().Single();

            ITypeProvider elementProvider;

            if (!context.TryGetTypeProvider(elementType, out elementProvider))
            {
                throw new Exception($"Unable to deserialise values of type {elementType} from MsgPack data.");
            }

            // read list length
            var count = ilg.DeclareLocal(typeof(int));

            ilg.Emit(OpCodes.Ldloc, unpacker);
            ilg.Emit(OpCodes.Ldloca, count);
            ilg.Emit(OpCodes.Call, typeof(Unpacker).GetMethod(nameof(Unpacker.TryReadArrayLength)));

            // verify read correctly
            var lbl1 = ilg.DefineLabel();

            ilg.Emit(OpCodes.Brtrue, lbl1);
            {
                ilg.Emit(OpCodes.Ldstr, "Expecting collection data to be encoded as array");
                ilg.LoadType(targetType);
                ilg.Emit(OpCodes.Newobj, typeof(DeserialisationException).GetConstructor(new[] { typeof(string), typeof(Type) }));
                ilg.Emit(OpCodes.Throw);
            }
            ilg.MarkLabel(lbl1);

            // create an array to store values
            ilg.Emit(OpCodes.Ldloc, count);
            ilg.Emit(OpCodes.Newarr, elementType);

            var array = ilg.DeclareLocal(elementType.MakeArrayType());

            ilg.Emit(OpCodes.Stloc, array);

            // begin loop
            var loopStart = ilg.DefineLabel();
            var loopTest  = ilg.DefineLabel();
            var loopEnd   = ilg.DefineLabel();

            var i = ilg.DeclareLocal(typeof(int));

            ilg.Emit(OpCodes.Ldc_I4_0);
            ilg.Emit(OpCodes.Stloc, i);

            ilg.Emit(OpCodes.Br, loopTest);
            ilg.MarkLabel(loopStart);

            // loop body
            var element = ilg.DeclareLocal(elementType);

            elementProvider.Deserialise(ilg, name, targetType, element, unpacker, contextLocal, context, unexpectedFieldBehaviour);

            ilg.Emit(OpCodes.Ldloc, array);
            ilg.Emit(OpCodes.Ldloc, i);
            ilg.Emit(OpCodes.Ldloc, element);
            ilg.Emit(OpCodes.Stelem, elementType);

            // loop counter increment
            ilg.Emit(OpCodes.Ldloc, i);
            ilg.Emit(OpCodes.Ldc_I4_1);
            ilg.Emit(OpCodes.Add);
            ilg.Emit(OpCodes.Stloc, i);

            // loop test
            ilg.MarkLabel(loopTest);
            ilg.Emit(OpCodes.Ldloc, i);
            ilg.Emit(OpCodes.Ldloc, count);
            ilg.Emit(OpCodes.Clt);
            ilg.Emit(OpCodes.Brtrue, loopStart);

            // after loop
            ilg.MarkLabel(loopEnd);

            ilg.Emit(OpCodes.Ldloc, array);
            ilg.Emit(OpCodes.Stloc, value);
        }
示例#5
0
        public void Serialise(ILGenerator ilg, LocalBuilder value, LocalBuilder packer, DasherContext context)
        {
            var type        = value.LocalType;
            var elementType = type.GetGenericArguments().Single();

            // read list length
            var count = ilg.DeclareLocal(typeof(int));

            ilg.Emit(OpCodes.Ldloc, value);
            ilg.Emit(OpCodes.Callvirt, typeof(IReadOnlyCollection <>).MakeGenericType(elementType).GetProperty(nameof(IReadOnlyList <int> .Count)).GetMethod);
            ilg.Emit(OpCodes.Stloc, count);

            // write array header
            ilg.Emit(OpCodes.Ldloc, packer);
            ilg.Emit(OpCodes.Ldloc, count);
            ilg.Emit(OpCodes.Call, typeof(UnsafePacker).GetMethod(nameof(UnsafePacker.PackArrayHeader)));

            // begin loop
            var loopStart = ilg.DefineLabel();
            var loopTest  = ilg.DefineLabel();
            var loopEnd   = ilg.DefineLabel();

            var i = ilg.DeclareLocal(typeof(int));

            ilg.Emit(OpCodes.Ldc_I4_0);
            ilg.Emit(OpCodes.Stloc, i);

            ilg.Emit(OpCodes.Br, loopTest);
            ilg.MarkLabel(loopStart);

            // loop body
            ilg.Emit(OpCodes.Ldloc, value);
            ilg.Emit(OpCodes.Ldloc, i);
            ilg.Emit(OpCodes.Callvirt, type.GetProperties(BindingFlags.Public | BindingFlags.Instance).Single(p => p.Name == "Item" && p.GetIndexParameters().Length == 1).GetMethod);
            var elementValue = ilg.DeclareLocal(elementType);

            ilg.Emit(OpCodes.Stloc, elementValue);

            ITypeProvider provider;

            if (!context.TryGetTypeProvider(elementValue.LocalType, out provider))
            {
                throw new Exception($"Cannot serialise IReadOnlyList<> element type {value.LocalType}.");
            }

            provider.Serialise(ilg, elementValue, packer, context);

            // loop counter increment
            ilg.Emit(OpCodes.Ldloc, i);
            ilg.Emit(OpCodes.Ldc_I4_1);
            ilg.Emit(OpCodes.Add);
            ilg.Emit(OpCodes.Stloc, i);

            // loop test
            ilg.MarkLabel(loopTest);
            ilg.Emit(OpCodes.Ldloc, i);
            ilg.Emit(OpCodes.Ldloc, count);
            ilg.Emit(OpCodes.Clt);
            ilg.Emit(OpCodes.Brtrue, loopStart);

            // after loop
            ilg.MarkLabel(loopEnd);
        }