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.

242 lines
13 KiB

  1. #nullable enable
  2. using System;
  3. using System.Collections.Generic;
  4. using System.Linq;
  5. using System.Text;
  6. using System.Threading.Tasks;
  7. using IPA.Config.Data;
  8. using IPA.Logging;
  9. namespace IPA.Config.Stores.Converters
  10. {
  11. /// <summary>
  12. /// A base class for all <see cref="ICollection{T}"/> type converters, providing most of the functionality.
  13. /// </summary>
  14. /// <typeparam name="T">the type of the items in the collection</typeparam>
  15. /// <typeparam name="TCollection">the instantiated type of collection</typeparam>
  16. public class CollectionConverter<T, TCollection> : ValueConverter<TCollection>
  17. where TCollection : ICollection<T?>
  18. {
  19. /// <summary>
  20. /// Creates a <see cref="CollectionConverter{T, TCollection}"/> using the default converter for the
  21. /// element type. Equivalent to calling <see cref="CollectionConverter{T, TCollection}.CollectionConverter(ValueConverter{T})"/>
  22. /// with <see cref="Converter{T}.Default"/>.
  23. /// </summary>
  24. /// <seealso cref="CollectionConverter{T, TCollection}.CollectionConverter(ValueConverter{T})"/>
  25. public CollectionConverter() : this(Converter<T>.Default) { }
  26. /// <summary>
  27. /// Creates a <see cref="CollectionConverter{T, TCollection}"/> using the specified underlying converter.
  28. /// </summary>
  29. /// <param name="underlying">the <see cref="ValueConverter{T}"/> to use to convert the values</param>
  30. public CollectionConverter(ValueConverter<T> underlying)
  31. => BaseConverter = underlying;
  32. /// <summary>
  33. /// Gets the converter for the collection's value type.
  34. /// </summary>
  35. protected ValueConverter<T> BaseConverter { get; }
  36. /// <summary>
  37. /// Creates a collection of type <typeparamref name="TCollection"/> using the <paramref name="size"/> and
  38. /// <paramref name="parent"/>.
  39. /// </summary>
  40. /// <param name="size">the initial size of the collecion</param>
  41. /// <param name="parent">the object that will own the new collection</param>
  42. /// <returns>a new instance of <typeparamref name="TCollection"/></returns>
  43. /// <seealso cref="ValueConverter{T}.FromValue(Value, object)"/>
  44. protected virtual TCollection Create(int size, object parent)
  45. => Activator.CreateInstance<TCollection>();
  46. /// <summary>
  47. /// Populates the colleciton <paramref name="col"/> with the deserialized values from <paramref name="list"/>
  48. /// with the parent <paramref name="parent"/>.
  49. /// </summary>
  50. /// <param name="col">the collection to populate</param>
  51. /// <param name="list">the values to populate it with</param>
  52. /// <param name="parent">the object that will own the new objects</param>
  53. /// <seealso cref="ValueConverter{T}.FromValue(Value, object)"/>
  54. protected void PopulateFromValue(TCollection col, List list, object parent)
  55. {
  56. if (list is null) throw new ArgumentNullException(nameof(list));
  57. foreach (var it in list)
  58. col.Add(BaseConverter.FromValue(it, parent));
  59. }
  60. /// <summary>
  61. /// Deserializes a <see cref="List"/> in <paramref name="value"/> into a new <typeparamref name="TCollection"/>
  62. /// owned by <paramref name="parent"/>.
  63. /// </summary>
  64. /// <param name="value">the <see cref="List"/> to convert to a <typeparamref name="TCollection"/></param>
  65. /// <param name="parent">the object that will own the resulting <typeparamref name="TCollection"/></param>
  66. /// <returns>a new <typeparamref name="TCollection"/> holding the deserialized content of <paramref name="value"/></returns>
  67. /// <seealso cref="ValueConverter{T}.FromValue(Value, object)"/>
  68. public override TCollection FromValue(Value? value, object parent)
  69. {
  70. if (value is not List list) throw new ArgumentException("Argument not a List", nameof(value));
  71. var col = Create(list.Count, parent);
  72. PopulateFromValue(col, list, parent);
  73. return col;
  74. }
  75. /// <summary>
  76. /// Serializes a <typeparamref name="TCollection"/> into a <see cref="List"/>.
  77. /// </summary>
  78. /// <param name="obj">the <typeparamref name="TCollection"/> to serialize</param>
  79. /// <param name="parent">the object owning <paramref name="obj"/></param>
  80. /// <returns>the <see cref="List"/> that <paramref name="obj"/> was serialized into</returns>
  81. /// <seealso cref="ValueConverter{T}.ToValue(T, object)"/>
  82. public override Value? ToValue(TCollection? obj, object parent)
  83. => Value.From(obj.Select(t => BaseConverter.ToValue(t, parent)));
  84. }
  85. /// <summary>
  86. /// A <see cref="CollectionConverter{T, TCollection}"/> which default constructs a converter for use as the value converter.
  87. /// </summary>
  88. /// <typeparam name="T">the value type of the collection</typeparam>
  89. /// <typeparam name="TCollection">the type of the colleciton</typeparam>
  90. /// <typeparam name="TConverter">the type of the converter to use for <typeparamref name="T"/></typeparam>
  91. /// <seealso cref="CollectionConverter{T, TCollection}"/>
  92. public sealed class CollectionConverter<T, TCollection, TConverter> : CollectionConverter<T, TCollection>
  93. where TCollection : ICollection<T?>
  94. where TConverter : ValueConverter<T>, new()
  95. {
  96. /// <summary>
  97. /// Creates a <see cref="CollectionConverter{T, TCollection}"/> using a default constructed <typeparamref name="TConverter"/>
  98. /// element type. Equivalent to calling <see cref="CollectionConverter{T, TCollection}.CollectionConverter(ValueConverter{T})"/>
  99. /// with a default-constructed <typeparamref name="TConverter"/>.
  100. /// </summary>
  101. /// <seealso cref="CollectionConverter{T, TCollection}.CollectionConverter(ValueConverter{T})"/>
  102. public CollectionConverter() : base(new TConverter()) { }
  103. }
  104. #if NET4
  105. /// <summary>
  106. /// A <see cref="CollectionConverter{T, TCollection}"/> for an <see cref="ISet{T}"/>, creating a <see cref="HashSet{T}"/> when deserializing.
  107. /// </summary>
  108. /// <typeparam name="T">the element type of the <see cref="ISet{T}"/></typeparam>
  109. /// <seealso cref="CollectionConverter{T, TCollection}"/>
  110. public class ISetConverter<T> : CollectionConverter<T, ISet<T?>>
  111. {
  112. /// <summary>
  113. /// Creates an <see cref="ISetConverter{T}"/> using the default converter for <typeparamref name="T"/>.
  114. /// </summary>
  115. /// <seealso cref="CollectionConverter{T, TCollection}.CollectionConverter()"/>
  116. public ISetConverter() : base() { }
  117. /// <summary>
  118. /// Creates an <see cref="ISetConverter{T}"/> using the specified underlying converter for values.
  119. /// </summary>
  120. /// <param name="underlying">the underlying <see cref="ValueConverter{T}"/> to use for the values</param>
  121. public ISetConverter(ValueConverter<T> underlying) : base(underlying) { }
  122. /// <summary>
  123. /// Creates a new <see cref="ISet{T}"/> (a <see cref="HashSet{T}"/>) for deserialization.
  124. /// </summary>
  125. /// <param name="size">the size to initialize it to</param>
  126. /// <param name="parent">the object that will own the new object</param>
  127. /// <returns>the new <see cref="ISet{T}"/></returns>
  128. protected override ISet<T?> Create(int size, object parent)
  129. => new HashSet<T?>();
  130. }
  131. /// <summary>
  132. /// An <see cref="ISetConverter{T}"/> which default constructs a converter for use as the value converter.
  133. /// </summary>
  134. /// <typeparam name="T">the value type of the collection</typeparam>
  135. /// <typeparam name="TConverter">the type of the converter to use for <typeparamref name="T"/></typeparam>
  136. /// <seealso cref="ISetConverter{T}"/>
  137. public sealed class ISetConverter<T, TConverter> : ISetConverter<T>
  138. where TConverter : ValueConverter<T>, new()
  139. {
  140. /// <summary>
  141. /// Creates an <see cref="ISetConverter{T}"/> using a default constructed <typeparamref name="TConverter"/>
  142. /// element type. Equivalent to calling <see cref="ISetConverter{T}.ISetConverter(ValueConverter{T})"/>
  143. /// with a default-constructed <typeparamref name="TConverter"/>.
  144. /// </summary>
  145. /// <seealso cref="ISetConverter{T}.ISetConverter(ValueConverter{T})"/>
  146. public ISetConverter() : base(new TConverter()) { }
  147. }
  148. #endif
  149. /// <summary>
  150. /// A <see cref="CollectionConverter{T, TCollection}"/> for a <see cref="List{T}"/>.
  151. /// </summary>
  152. /// <typeparam name="T">the element type of the <see cref="List{T}"/></typeparam>
  153. /// <seealso cref="CollectionConverter{T, TCollection}"/>
  154. public class ListConverter<T> : CollectionConverter<T, List<T?>>
  155. {
  156. /// <summary>
  157. /// Creates an <see cref="ListConverter{T}"/> using the default converter for <typeparamref name="T"/>.
  158. /// </summary>
  159. /// <seealso cref="CollectionConverter{T, TCollection}.CollectionConverter()"/>
  160. public ListConverter() : base() { }
  161. /// <summary>
  162. /// Creates an <see cref="ListConverter{T}"/> using the specified underlying converter for values.
  163. /// </summary>
  164. /// <param name="underlying">the underlying <see cref="ValueConverter{T}"/> to use for the values</param>
  165. public ListConverter(ValueConverter<T> underlying) : base(underlying) { }
  166. /// <summary>
  167. /// Creates a new <see cref="List{T}"/> for deserialization.
  168. /// </summary>
  169. /// <param name="size">the size to initialize it to</param>
  170. /// <param name="parent">the object that will own the new object</param>
  171. /// <returns>the new <see cref="List{T}"/></returns>
  172. protected override List<T?> Create(int size, object parent)
  173. => new(size);
  174. }
  175. /// <summary>
  176. /// A <see cref="ListConverter{T}"/> which default constructs a converter for use as the value converter.
  177. /// </summary>
  178. /// <typeparam name="T">the value type of the collection</typeparam>
  179. /// <typeparam name="TConverter">the type of the converter to use for <typeparamref name="T"/></typeparam>
  180. /// <seealso cref="ListConverter{T}"/>
  181. public sealed class ListConverter<T, TConverter> : ListConverter<T>
  182. where TConverter : ValueConverter<T>, new()
  183. {
  184. /// <summary>
  185. /// Creates an <see cref="ListConverter{T}"/> using a default constructed <typeparamref name="TConverter"/>
  186. /// element type. Equivalent to calling <see cref="ListConverter{T}.ListConverter(ValueConverter{T})"/>
  187. /// with a default-constructed <typeparamref name="TConverter"/>.
  188. /// </summary>
  189. /// <seealso cref="ListConverter{T}.ListConverter(ValueConverter{T})"/>
  190. public ListConverter() : base(new TConverter()) { }
  191. }
  192. /// <summary>
  193. /// A <see cref="CollectionConverter{T, TCollection}"/> for an <see cref="IList{T}"/>, creating a <see cref="List{T}"/> when deserializing.
  194. /// </summary>
  195. /// <typeparam name="T">the element type of the <see cref="IList{T}"/></typeparam>
  196. /// <seealso cref="CollectionConverter{T, TCollection}"/>
  197. public class IListConverter<T> : CollectionConverter<T, IList<T?>>
  198. {
  199. /// <summary>
  200. /// Creates an <see cref="IListConverter{T}"/> using the default converter for <typeparamref name="T"/>.
  201. /// </summary>
  202. /// <seealso cref="CollectionConverter{T, TCollection}.CollectionConverter()"/>
  203. public IListConverter() : base() { }
  204. /// <summary>
  205. /// Creates an <see cref="IListConverter{T}"/> using the specified underlying converter for values.
  206. /// </summary>
  207. /// <param name="underlying">the underlying <see cref="ValueConverter{T}"/> to use for the values</param>
  208. public IListConverter(ValueConverter<T> underlying) : base(underlying) { }
  209. /// <summary>
  210. /// Creates a new <see cref="IList{T}"/> (a <see cref="List{T}"/>) for deserialization.
  211. /// </summary>
  212. /// <param name="size">the size to initialize it to</param>
  213. /// <param name="parent">the object that will own the new object</param>
  214. /// <returns>the new <see cref="IList{T}"/></returns>
  215. protected override IList<T?> Create(int size, object parent)
  216. => new List<T?>(size);
  217. }
  218. /// <summary>
  219. /// An <see cref="IListConverter{T}"/> which default constructs a converter for use as the value converter.
  220. /// </summary>
  221. /// <typeparam name="T">the value type of the collection</typeparam>
  222. /// <typeparam name="TConverter">the type of the converter to use for <typeparamref name="T"/></typeparam>
  223. /// <seealso cref="IListConverter{T}"/>
  224. public sealed class IListConverter<T, TConverter> : IListConverter<T>
  225. where TConverter : ValueConverter<T>, new()
  226. {
  227. /// <summary>
  228. /// Creates an <see cref="IListConverter{T}"/> using a default constructed <typeparamref name="TConverter"/>
  229. /// element type. Equivalent to calling <see cref="IListConverter{T}.IListConverter(ValueConverter{T})"/>
  230. /// with a default-constructed <typeparamref name="TConverter"/>.
  231. /// </summary>
  232. /// <seealso cref="IListConverter{T}.IListConverter(ValueConverter{T})"/>
  233. public IListConverter() : base(new TConverter()) { }
  234. }
  235. }