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.

88 lines
4.3 KiB

  1. using IPA.Config.Data;
  2. using System;
  3. namespace IPA.Config.Stores.Converters
  4. {
  5. /// <summary>
  6. /// A <see cref="ValueConverter{T}"/> for objects normally serialized to config via <see cref="GeneratedStore.Generated{T}(Config, bool)"/>.
  7. /// </summary>
  8. /// <typeparam name="T">the same type parameter that would be passed into <see cref="GeneratedStore.Generated{T}(Config, bool)"/></typeparam>
  9. /// <seealso cref="GeneratedStore.Generated{T}(Config, bool)"/>
  10. public class CustomObjectConverter<T> : ValueConverter<T> where T : class
  11. {
  12. private interface IImpl
  13. {
  14. T FromValue(Value value, object parent);
  15. Value ToValue(T obj, object parent);
  16. }
  17. private class Impl<U> : IImpl where U : class, GeneratedStoreImpl.IGeneratedStore<T>, T
  18. {
  19. private static readonly GeneratedStoreImpl.GeneratedStoreCreator creator = GeneratedStoreImpl.GetCreator(typeof(T));
  20. private static U Create(GeneratedStoreImpl.IGeneratedStore parent)
  21. => creator(parent) as U;
  22. public T FromValue(Value value, object parent)
  23. { // lots of casting here, but it works i promise (probably) (parent can be a non-IGeneratedStore, however it won't necessarily behave then)
  24. var obj = Create(parent as GeneratedStoreImpl.IGeneratedStore);
  25. obj.Deserialize(value);
  26. return obj;
  27. }
  28. public Value ToValue(T obj, object parent)
  29. {
  30. if (obj is GeneratedStoreImpl.IGeneratedStore store)
  31. return store.Serialize();
  32. else
  33. {
  34. var newObj = Create(null);
  35. newObj.CopyFrom(obj, false); // don't use lock because it won't be used
  36. return newObj.Serialize();
  37. }
  38. }
  39. }
  40. private static readonly IImpl impl = (IImpl)Activator.CreateInstance(
  41. typeof(Impl<>).MakeGenericType(GeneratedStoreImpl.GetGeneratedType(typeof(T))));
  42. /// <summary>
  43. /// Deserializes <paramref name="value"/> into a <typeparamref name="T"/> with the given <paramref name="parent"/>.
  44. /// </summary>
  45. /// <param name="value">the <see cref="Value"/> to deserialize</param>
  46. /// <param name="parent">the parent object that will own the deserialized value</param>
  47. /// <returns>the deserialized value</returns>
  48. /// <seealso cref="ValueConverter{T}.FromValue(Value, object)"/>
  49. public static T Deserialize(Value value, object parent)
  50. => impl.FromValue(value, parent);
  51. /// <summary>
  52. /// Serializes <paramref name="obj"/> into a <see cref="Value"/> structure, given <paramref name="parent"/>.
  53. /// </summary>
  54. /// <param name="obj">the object to serialize</param>
  55. /// <param name="parent">the parent object that owns <paramref name="obj"/></param>
  56. /// <returns>the <see cref="Value"/> tree that represents <paramref name="obj"/></returns>
  57. /// <seealso cref="ValueConverter{T}.ToValue(T, object)"/>
  58. public static Value Serialize(T obj, object parent)
  59. => impl.ToValue(obj, parent);
  60. /// <summary>
  61. /// Deserializes <paramref name="value"/> into a <typeparamref name="T"/> with the given <paramref name="parent"/>.
  62. /// </summary>
  63. /// <param name="value">the <see cref="Value"/> to deserialize</param>
  64. /// <param name="parent">the parent object that will own the deserialized value</param>
  65. /// <returns>the deserialized value</returns>
  66. /// <seealso cref="ValueConverter{T}.FromValue(Value, object)"/>
  67. public override T FromValue(Value value, object parent)
  68. => impl.FromValue(value, parent);
  69. /// <summary>
  70. /// Serializes <paramref name="obj"/> into a <see cref="Value"/> structure, given <paramref name="parent"/>.
  71. /// </summary>
  72. /// <param name="obj">the object to serialize</param>
  73. /// <param name="parent">the parent object that owns <paramref name="obj"/></param>
  74. /// <returns>the <see cref="Value"/> tree that represents <paramref name="obj"/></returns>
  75. /// <seealso cref="ValueConverter{T}.ToValue(T, object)"/>
  76. public override Value ToValue(T obj, object parent)
  77. => impl.ToValue(obj, parent);
  78. }
  79. }