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.

143 lines
7.2 KiB

  1. #nullable enable
  2. using IPA.Config.Data;
  3. using System;
  4. namespace IPA.Config.Stores.Converters
  5. {
  6. /// <summary>
  7. /// A <see cref="ValueConverter{T}"/> for objects normally serialized to config via <see cref="GeneratedStore.Generated{T}(Config, bool)"/>.
  8. /// </summary>
  9. /// <typeparam name="T">the same type parameter that would be passed into <see cref="GeneratedStore.Generated{T}(Config, bool)"/></typeparam>
  10. /// <seealso cref="GeneratedStore.Generated{T}(Config, bool)"/>
  11. public class CustomObjectConverter<T> : ValueConverter<T> where T : class
  12. {
  13. private interface IImpl
  14. {
  15. T? FromValue(Value? value, object parent);
  16. Value? ToValue(T? obj, object parent);
  17. }
  18. private class Impl<U> : IImpl where U : class, GeneratedStoreImpl.IGeneratedStore<T>, T
  19. {
  20. private static readonly GeneratedStoreImpl.GeneratedStoreCreator creator = GeneratedStoreImpl.GetCreator(typeof(T));
  21. private static U Create(GeneratedStoreImpl.IGeneratedStore? parent)
  22. => (U)creator(parent);
  23. public T? FromValue(Value? value, object parent)
  24. { // lots of casting here, but it works i promise (probably) (parent can be a non-IGeneratedStore, however it won't necessarily behave then)
  25. if (value is null) return null;
  26. var obj = Create(parent as GeneratedStoreImpl.IGeneratedStore);
  27. obj.Deserialize(value);
  28. return obj;
  29. }
  30. public Value? ToValue(T? obj, object parent)
  31. {
  32. if (obj is null) return null;
  33. if (obj is GeneratedStoreImpl.IGeneratedStore store)
  34. return store.Serialize();
  35. else
  36. {
  37. var newObj = Create(null);
  38. newObj.CopyFrom(obj, false); // don't use lock because it won't be used
  39. return newObj.Serialize();
  40. }
  41. }
  42. }
  43. private static readonly IImpl impl = (IImpl)Activator.CreateInstance(
  44. typeof(Impl<>).MakeGenericType(typeof(T), GeneratedStoreImpl.GetGeneratedType(typeof(T))));
  45. /// <summary>
  46. /// Deserializes <paramref name="value"/> into a <typeparamref name="T"/> with the given <paramref name="parent"/>.
  47. /// </summary>
  48. /// <param name="value">the <see cref="Value"/> to deserialize</param>
  49. /// <param name="parent">the parent object that will own the deserialized value</param>
  50. /// <returns>the deserialized value</returns>
  51. /// <seealso cref="ValueConverter{T}.FromValue(Value, object)"/>
  52. public static T? Deserialize(Value? value, object parent)
  53. => impl.FromValue(value, parent);
  54. /// <summary>
  55. /// Serializes <paramref name="obj"/> into a <see cref="Value"/> structure, given <paramref name="parent"/>.
  56. /// </summary>
  57. /// <param name="obj">the object to serialize</param>
  58. /// <param name="parent">the parent object that owns <paramref name="obj"/></param>
  59. /// <returns>the <see cref="Value"/> tree that represents <paramref name="obj"/></returns>
  60. /// <seealso cref="ValueConverter{T}.ToValue(T, object)"/>
  61. public static Value? Serialize(T? obj, object parent)
  62. => impl.ToValue(obj, parent);
  63. /// <summary>
  64. /// Deserializes <paramref name="value"/> into a <typeparamref name="T"/> with the given <paramref name="parent"/>.
  65. /// </summary>
  66. /// <param name="value">the <see cref="Value"/> to deserialize</param>
  67. /// <param name="parent">the parent object that will own the deserialized value</param>
  68. /// <returns>the deserialized value</returns>
  69. /// <seealso cref="ValueConverter{T}.FromValue(Value, object)"/>
  70. public override T? FromValue(Value? value, object parent)
  71. => Deserialize(value, parent);
  72. /// <summary>
  73. /// Serializes <paramref name="obj"/> into a <see cref="Value"/> structure, given <paramref name="parent"/>.
  74. /// </summary>
  75. /// <param name="obj">the object to serialize</param>
  76. /// <param name="parent">the parent object that owns <paramref name="obj"/></param>
  77. /// <returns>the <see cref="Value"/> tree that represents <paramref name="obj"/></returns>
  78. /// <seealso cref="ValueConverter{T}.ToValue(T, object)"/>
  79. public override Value? ToValue(T? obj, object parent)
  80. => Serialize(obj, parent);
  81. }
  82. /// <summary>
  83. /// A <see cref="ValueConverter{T}"/> for custom value types, serialized identically to the reference types serialized with
  84. /// <see cref="GeneratedStore.Generated{T}(Config, bool)"/>.
  85. /// </summary>
  86. /// <typeparam name="T">the type of the value to convert</typeparam>
  87. public class CustomValueTypeConverter<T> : ValueConverter<T> where T : struct
  88. {
  89. private static readonly GeneratedStoreImpl.SerializeObject<T> serialize
  90. = GeneratedStoreImpl.GetSerializerDelegate<T>();
  91. private static readonly GeneratedStoreImpl.DeserializeObject<T> deserialize
  92. = GeneratedStoreImpl.GetDeserializerDelegate<T>();
  93. /// <summary>
  94. /// Deserializes <paramref name="value"/> into a <typeparamref name="T"/> with the given <paramref name="parent"/>.
  95. /// </summary>
  96. /// <param name="value">the <see cref="Value"/> to deserialize</param>
  97. /// <param name="parent">the parent object that will own the deserialized value</param>
  98. /// <returns>the deserialized value</returns>
  99. /// <seealso cref="ValueConverter{T}.FromValue(Value, object)"/>
  100. public static T Deserialize(Value? value, object parent)
  101. => deserialize(value, parent);
  102. /// <summary>
  103. /// Serializes <paramref name="obj"/> into a corresponding <see cref="Value"/> structure.
  104. /// </summary>
  105. /// <param name="obj">the object to serialize</param>
  106. /// <returns>the <see cref="Value"/> tree that represents <paramref name="obj"/></returns>
  107. /// <seealso cref="ValueConverter{T}.ToValue(T, object)"/>
  108. public static Value Serialize(T obj)
  109. => serialize(obj);
  110. /// <summary>
  111. /// Deserializes <paramref name="value"/> into a <typeparamref name="T"/> with the given <paramref name="parent"/>.
  112. /// </summary>
  113. /// <param name="value">the <see cref="Value"/> to deserialize</param>
  114. /// <param name="parent">the parent object that will own the deserialized value</param>
  115. /// <returns>the deserialized value</returns>
  116. /// <seealso cref="ValueConverter{T}.FromValue(Value, object)"/>
  117. public override T FromValue(Value? value, object parent)
  118. => Deserialize(value, parent);
  119. /// <summary>
  120. /// Serializes <paramref name="obj"/> into a <see cref="Value"/> structure, given <paramref name="parent"/>.
  121. /// </summary>
  122. /// <param name="obj">the object to serialize</param>
  123. /// <param name="parent">the parent object that owns <paramref name="obj"/></param>
  124. /// <returns>the <see cref="Value"/> tree that represents <paramref name="obj"/></returns>
  125. /// <seealso cref="ValueConverter{T}.ToValue(T, object)"/>
  126. public override Value? ToValue(T obj, object parent)
  127. => Serialize(obj);
  128. }
  129. }