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.

179 lines
7.4 KiB

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