using IPA.Config.Data; using System; using System.Collections.Generic; using System.Linq; using System.Reflection; using System.Reflection.Emit; using System.Text; using System.Threading.Tasks; namespace IPA.Config.Stores { internal static partial class GeneratedStoreImpl { internal delegate Value SerializeObject(T obj); internal delegate T DeserializeObject(Value val, object parent); private static class DelegateStore { public static SerializeObject Serialize; public static DeserializeObject Deserialize; } internal static SerializeObject GetSerializerDelegate() => DelegateStore.Serialize ??= GetSerializerDelegateInternal(); private static SerializeObject GetSerializerDelegateInternal() { var type = typeof(T); #if DEBUG var defType = Module.DefineType($"{type.FullName}", TypeAttributes.Public | TypeAttributes.Sealed | TypeAttributes.Abstract); var dynMethod = defType.DefineMethod("SerializeType", MethodAttributes.Public | MethodAttributes.Static, typeof(Value), new[] { type }); #else var dynMethod = new DynamicMethod($"SerializeType>>{type.FullName}", typeof(Value), new[] { type }, Module, true); #endif var structure = ReadObjectMembers(type); //CreateAndInitializeConvertersFor(type, structure); var loadObject = type.IsValueType ? (Action)(il => il.Emit(OpCodes.Ldarga_S, 0)) : il => il.Emit(OpCodes.Ldarg_0); { var il = dynMethod.GetILGenerator(); var GetLocal = MakeLocalAllocator(il); EmitLogError(il, $"Entered SerializeType delegate for type {type}"); if (!type.IsValueType) { var notIGeneratedStore = il.DefineLabel(); var IGeneratedStore_t = typeof(IGeneratedStore); var IGeneratedStore_Serialize = IGeneratedStore_t.GetMethod(nameof(IGeneratedStore.Serialize)); il.Emit(OpCodes.Ldarg_0); il.Emit(OpCodes.Isinst, IGeneratedStore_t); il.Emit(OpCodes.Brfalse, notIGeneratedStore); il.Emit(OpCodes.Ldarg_0); il.Emit(OpCodes.Castclass, IGeneratedStore_t); il.Emit(OpCodes.Callvirt, IGeneratedStore_Serialize); il.Emit(OpCodes.Ret); il.MarkLabel(notIGeneratedStore); } EmitLogError(il, $"Serializing structure of {type}"); EmitSerializeStructure(il, structure, GetLocal, loadObject); il.Emit(OpCodes.Ret); } #if DEBUG defType.CreateType(); return (SerializeObject)Delegate.CreateDelegate(typeof(SerializeObject), dynMethod); #else return (SerializeObject)dynMethod.CreateDelegate(typeof(SerializeObject)); #endif } internal static DeserializeObject GetDeserializerDelegate() => DelegateStore.Deserialize ??= GetDeserializerDelegateInternal(); private static DeserializeObject GetDeserializerDelegateInternal() { var type = typeof(T); //var dynMethod = new DynamicMethod($"DeserializeType>>{type.FullName}", type, new[] { typeof(Value), typeof(object) }, Module, true); #if DEBUG var defType = Module.DefineType($"{type.FullName}", TypeAttributes.Public | TypeAttributes.Sealed | TypeAttributes.Abstract); var dynMethod = defType.DefineMethod("DeserializeType", MethodAttributes.Public | MethodAttributes.Static, type, new[] { typeof(Value), typeof(object) }); #else var dynMethod = new DynamicMethod($"DeserializeType>>{type.FullName}", type, new[] { typeof(Value), typeof(object) }, Module, true); #endif var structure = ReadObjectMembers(type); //CreateAndInitializeConvertersFor(type, structure); { var il = dynMethod.GetILGenerator(); var GetLocal = MakeLocalAllocator(il); var IGeneratedStore_t = typeof(IGeneratedStore); var IGeneratedStore_Deserialize = IGeneratedStore_t.GetMethod(nameof(IGeneratedStore.Deserialize)); void ParentObj(ILGenerator il) { il.Emit(OpCodes.Ldarg_1); il.Emit(OpCodes.Isinst, IGeneratedStore_t); } EmitLogError(il, $"Entered DeserializeType delegate for type {type}"); if (!type.IsValueType) { EmitLogError(il, $"Forwarding to created type serialization"); EmitCreateChildGenerated(il, type, ParentObj); il.Emit(OpCodes.Dup); il.Emit(OpCodes.Castclass, IGeneratedStore_t); il.Emit(OpCodes.Ldarg_0); il.Emit(OpCodes.Callvirt, IGeneratedStore_Deserialize); il.Emit(OpCodes.Ret); } else { var Map_t = typeof(Map); var Map_TryGetValue = Map_t.GetMethod(nameof(Map.TryGetValue)); var Object_GetType = typeof(object).GetMethod(nameof(Object.GetType)); var valueLocal = il.DeclareLocal(typeof(Value)); var mapLocal = il.DeclareLocal(typeof(Map)); var resultLocal = il.DeclareLocal(type); var nonNull = il.DefineLabel(); EmitLogError(il, $"Deserializing structure of {type}"); il.Emit(OpCodes.Ldarg_0); il.Emit(OpCodes.Brtrue, nonNull); EmitLogError(il, "Attempting to deserialize null", tailcall: false); il.Emit(OpCodes.Ldloc, resultLocal); il.Emit(OpCodes.Ret); il.MarkLabel(nonNull); il.Emit(OpCodes.Ldarg_0); il.Emit(OpCodes.Isinst, Map_t); il.Emit(OpCodes.Dup); // duplicate cloned value il.Emit(OpCodes.Stloc, mapLocal); var notMapError = il.DefineLabel(); il.Emit(OpCodes.Brtrue, notMapError); // handle error EmitLogError(il, $"Invalid root for deserializing {type.FullName}", tailcall: false, expected: il => EmitTypeof(il, Map_t), found: il => { il.Emit(OpCodes.Ldarg_0); il.Emit(OpCodes.Callvirt, Object_GetType); }); il.Emit(OpCodes.Ldloc, resultLocal); il.Emit(OpCodes.Ret); il.MarkLabel(notMapError); EmitDeserializeStructure(il, structure, mapLocal, valueLocal, GetLocal, il => il.Emit(OpCodes.Ldloca, resultLocal), ParentObj); il.Emit(OpCodes.Ldloc, resultLocal); il.Emit(OpCodes.Ret); } } #if DEBUG defType.CreateType(); return (DeserializeObject)Delegate.CreateDelegate(typeof(DeserializeObject), dynMethod); #else return (DeserializeObject)dynMethod.CreateDelegate(typeof(DeserializeObject)); #endif } } }