You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

178 lines
7.4 KiB

  1. using IPA.Config.Data;
  2. using System;
  3. using System.Collections.Generic;
  4. using System.Linq;
  5. using System.Reflection;
  6. using System.Reflection.Emit;
  7. using System.Text;
  8. using System.Threading.Tasks;
  9. namespace IPA.Config.Stores
  10. {
  11. internal static partial class GeneratedStoreImpl
  12. {
  13. internal delegate Value SerializeObject<T>(T obj);
  14. internal delegate T DeserializeObject<T>(Value val, object parent);
  15. private static class DelegateStore<T>
  16. {
  17. public static SerializeObject<T> Serialize;
  18. public static DeserializeObject<T> Deserialize;
  19. }
  20. internal static SerializeObject<T> GetSerializerDelegate<T>()
  21. => DelegateStore<T>.Serialize ??= GetSerializerDelegateInternal<T>();
  22. private static SerializeObject<T> GetSerializerDelegateInternal<T>()
  23. {
  24. var type = typeof(T);
  25. #if DEBUG
  26. var defType = Module.DefineType($"{type.FullName}<SerializeTypeContainer>", TypeAttributes.Public | TypeAttributes.Sealed | TypeAttributes.Abstract);
  27. var dynMethod = defType.DefineMethod("SerializeType", MethodAttributes.Public | MethodAttributes.Static, typeof(Value), new[] { type });
  28. #else
  29. var dynMethod = new DynamicMethod($"SerializeType>>{type.FullName}", typeof(Value), new[] { type }, Module, true);
  30. #endif
  31. var structure = ReadObjectMembers(type);
  32. //CreateAndInitializeConvertersFor(type, structure);
  33. var loadObject = type.IsValueType
  34. ? (Action<ILGenerator>)(il => il.Emit(OpCodes.Ldarga_S, 0))
  35. : il => il.Emit(OpCodes.Ldarg_0);
  36. var loadParent = type.IsValueType
  37. ? (Action<ILGenerator>)(il => il.Emit(OpCodes.Ldnull))
  38. : loadObject;
  39. {
  40. var il = dynMethod.GetILGenerator();
  41. var GetLocal = MakeLocalAllocator(il);
  42. if (!type.IsValueType)
  43. {
  44. var notIGeneratedStore = il.DefineLabel();
  45. var IGeneratedStore_t = typeof(IGeneratedStore);
  46. var IGeneratedStore_Serialize = IGeneratedStore_t.GetMethod(nameof(IGeneratedStore.Serialize));
  47. il.Emit(OpCodes.Ldarg_0);
  48. il.Emit(OpCodes.Isinst, IGeneratedStore_t);
  49. il.Emit(OpCodes.Brfalse, notIGeneratedStore);
  50. il.Emit(OpCodes.Ldarg_0);
  51. il.Emit(OpCodes.Castclass, IGeneratedStore_t);
  52. il.Emit(OpCodes.Callvirt, IGeneratedStore_Serialize);
  53. il.Emit(OpCodes.Ret);
  54. il.MarkLabel(notIGeneratedStore);
  55. }
  56. EmitSerializeStructure(il, structure, GetLocal, loadObject, loadParent);
  57. il.Emit(OpCodes.Ret);
  58. }
  59. #if DEBUG
  60. defType.CreateType();
  61. return (SerializeObject<T>)Delegate.CreateDelegate(typeof(SerializeObject<T>), dynMethod);
  62. #else
  63. return (SerializeObject<T>)dynMethod.CreateDelegate(typeof(SerializeObject<T>));
  64. #endif
  65. }
  66. internal static DeserializeObject<T> GetDeserializerDelegate<T>()
  67. => DelegateStore<T>.Deserialize ??= GetDeserializerDelegateInternal<T>();
  68. private static DeserializeObject<T> GetDeserializerDelegateInternal<T>()
  69. {
  70. var type = typeof(T);
  71. //var dynMethod = new DynamicMethod($"DeserializeType>>{type.FullName}", type, new[] { typeof(Value), typeof(object) }, Module, true);
  72. #if DEBUG
  73. var defType = Module.DefineType($"{type.FullName}<DeserializeTypeContainer>", TypeAttributes.Public | TypeAttributes.Sealed | TypeAttributes.Abstract);
  74. var dynMethod = defType.DefineMethod("DeserializeType", MethodAttributes.Public | MethodAttributes.Static, type, new[] { typeof(Value), typeof(object) });
  75. #else
  76. var dynMethod = new DynamicMethod($"DeserializeType>>{type.FullName}", type, new[] { typeof(Value), typeof(object) }, Module, true);
  77. #endif
  78. var structure = ReadObjectMembers(type);
  79. //CreateAndInitializeConvertersFor(type, structure);
  80. {
  81. var il = dynMethod.GetILGenerator();
  82. var GetLocal = MakeLocalAllocator(il);
  83. var IGeneratedStore_t = typeof(IGeneratedStore);
  84. var IGeneratedStore_Deserialize = IGeneratedStore_t.GetMethod(nameof(IGeneratedStore.Deserialize));
  85. void ParentObj(ILGenerator il)
  86. {
  87. il.Emit(OpCodes.Ldarg_1);
  88. il.Emit(OpCodes.Isinst, IGeneratedStore_t);
  89. }
  90. if (!type.IsValueType)
  91. {
  92. EmitCreateChildGenerated(il, type, ParentObj);
  93. il.Emit(OpCodes.Dup);
  94. il.Emit(OpCodes.Castclass, IGeneratedStore_t);
  95. il.Emit(OpCodes.Ldarg_0);
  96. il.Emit(OpCodes.Callvirt, IGeneratedStore_Deserialize);
  97. il.Emit(OpCodes.Ret);
  98. }
  99. else
  100. {
  101. var Map_t = typeof(Map);
  102. var Map_TryGetValue = Map_t.GetMethod(nameof(Map.TryGetValue));
  103. var Object_GetType = typeof(object).GetMethod(nameof(Object.GetType));
  104. var valueLocal = il.DeclareLocal(typeof(Value));
  105. var mapLocal = il.DeclareLocal(typeof(Map));
  106. var resultLocal = il.DeclareLocal(type);
  107. var nonNull = il.DefineLabel();
  108. il.Emit(OpCodes.Ldarg_0);
  109. il.Emit(OpCodes.Brtrue, nonNull);
  110. EmitLogError(il, "Attempting to deserialize null", tailcall: false);
  111. il.Emit(OpCodes.Ldloc, resultLocal);
  112. il.Emit(OpCodes.Ret);
  113. il.MarkLabel(nonNull);
  114. il.Emit(OpCodes.Ldarg_0);
  115. il.Emit(OpCodes.Isinst, Map_t);
  116. il.Emit(OpCodes.Dup); // duplicate cloned value
  117. il.Emit(OpCodes.Stloc, mapLocal);
  118. var notMapError = il.DefineLabel();
  119. il.Emit(OpCodes.Brtrue, notMapError);
  120. // handle error
  121. EmitLogError(il, $"Invalid root for deserializing {type.FullName}", tailcall: false,
  122. expected: il => EmitTypeof(il, Map_t), found: il =>
  123. {
  124. il.Emit(OpCodes.Ldarg_0);
  125. il.Emit(OpCodes.Callvirt, Object_GetType);
  126. });
  127. il.Emit(OpCodes.Ldloc, resultLocal);
  128. il.Emit(OpCodes.Ret);
  129. il.MarkLabel(notMapError);
  130. EmitDeserializeStructure(il, structure, mapLocal, valueLocal, GetLocal, il => il.Emit(OpCodes.Ldloca, resultLocal), ParentObj);
  131. il.Emit(OpCodes.Ldloc, resultLocal);
  132. il.Emit(OpCodes.Ret);
  133. }
  134. }
  135. #if DEBUG
  136. defType.CreateType();
  137. return (DeserializeObject<T>)Delegate.CreateDelegate(typeof(DeserializeObject<T>), dynMethod);
  138. #else
  139. return (DeserializeObject<T>)dynMethod.CreateDelegate(typeof(DeserializeObject<T>));
  140. #endif
  141. }
  142. }
  143. }