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); } }
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); }
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); }
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); }
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); }