|
|
@ -0,0 +1,183 @@ |
|
|
|
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>(T obj); |
|
|
|
internal delegate T DeserializeObject<T>(Value val, object parent); |
|
|
|
|
|
|
|
private static class DelegateStore<T> |
|
|
|
{ |
|
|
|
public static SerializeObject<T> Serialize; |
|
|
|
public static DeserializeObject<T> Deserialize; |
|
|
|
} |
|
|
|
|
|
|
|
internal static SerializeObject<T> GetSerializerDelegate<T>() |
|
|
|
=> DelegateStore<T>.Serialize ??= GetSerializerDelegateInternal<T>(); |
|
|
|
|
|
|
|
private static SerializeObject<T> GetSerializerDelegateInternal<T>() |
|
|
|
{ |
|
|
|
var type = typeof(T); |
|
|
|
#if DEBUG
|
|
|
|
var defType = Module.DefineType($"{type.FullName}<SerializeTypeContainer>", 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<ILGenerator>)(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<T>)Delegate.CreateDelegate(typeof(SerializeObject<T>), dynMethod); |
|
|
|
#else
|
|
|
|
return (SerializeObject<T>)dynMethod.CreateDelegate(typeof(SerializeObject<T>)); |
|
|
|
#endif
|
|
|
|
} |
|
|
|
|
|
|
|
internal static DeserializeObject<T> GetDeserializerDelegate<T>() |
|
|
|
=> DelegateStore<T>.Deserialize ??= GetDeserializerDelegateInternal<T>(); |
|
|
|
|
|
|
|
private static DeserializeObject<T> GetDeserializerDelegateInternal<T>() |
|
|
|
{ |
|
|
|
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}<DeserializeTypeContainer>", 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<T>)Delegate.CreateDelegate(typeof(DeserializeObject<T>), dynMethod); |
|
|
|
#else
|
|
|
|
return (DeserializeObject<T>)dynMethod.CreateDelegate(typeof(DeserializeObject<T>)); |
|
|
|
#endif
|
|
|
|
} |
|
|
|
} |
|
|
|
} |