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.

237 lines
13 KiB

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