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.

239 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. #if NET4
  102. /// <summary>
  103. /// A <see cref="CollectionConverter{T, TCollection}"/> for an <see cref="ISet{T}"/>, creating a <see cref="HashSet{T}"/> when deserializing.
  104. /// </summary>
  105. /// <typeparam name="T">the element type of the <see cref="ISet{T}"/></typeparam>
  106. /// <seealso cref="CollectionConverter{T, TCollection}"/>
  107. public class ISetConverter<T> : CollectionConverter<T, ISet<T>>
  108. {
  109. /// <summary>
  110. /// Creates an <see cref="ISetConverter{T}"/> using the default converter for <typeparamref name="T"/>.
  111. /// </summary>
  112. /// <seealso cref="CollectionConverter{T, TCollection}.CollectionConverter()"/>
  113. public ISetConverter() : base() { }
  114. /// <summary>
  115. /// Creates an <see cref="ISetConverter{T}"/> using the specified underlying converter for values.
  116. /// </summary>
  117. /// <param name="underlying">the underlying <see cref="ValueConverter{T}"/> to use for the values</param>
  118. public ISetConverter(ValueConverter<T> underlying) : base(underlying) { }
  119. /// <summary>
  120. /// Creates a new <see cref="ISet{T}"/> (a <see cref="HashSet{T}"/>) for deserialization.
  121. /// </summary>
  122. /// <param name="size">the size to initialize it to</param>
  123. /// <param name="parent">the object that will own the new object</param>
  124. /// <returns>the new <see cref="ISet{T}"/></returns>
  125. protected override ISet<T> Create(int size, object parent)
  126. => new HashSet<T>();
  127. }
  128. /// <summary>
  129. /// An <see cref="ISetConverter{T}"/> which default constructs a converter for use as the value converter.
  130. /// </summary>
  131. /// <typeparam name="T">the value type of the collection</typeparam>
  132. /// <typeparam name="TConverter">the type of the converter to use for <typeparamref name="T"/></typeparam>
  133. /// <seealso cref="ISetConverter{T}"/>
  134. public sealed class ISetConverter<T, TConverter> : ISetConverter<T>
  135. where TConverter : ValueConverter<T>, new()
  136. {
  137. /// <summary>
  138. /// Creates an <see cref="ISetConverter{T}"/> using a default constructed <typeparamref name="TConverter"/>
  139. /// element type. Equivalent to calling <see cref="ISetConverter{T}.ISetConverter(ValueConverter{T})"/>
  140. /// with a default-constructed <typeparamref name="TConverter"/>.
  141. /// </summary>
  142. /// <seealso cref="ISetConverter{T}.ISetConverter(ValueConverter{T})"/>
  143. public ISetConverter() : base(new TConverter()) { }
  144. }
  145. #endif
  146. /// <summary>
  147. /// A <see cref="CollectionConverter{T, TCollection}"/> for a <see cref="List{T}"/>.
  148. /// </summary>
  149. /// <typeparam name="T">the element type of the <see cref="List{T}"/></typeparam>
  150. /// <seealso cref="CollectionConverter{T, TCollection}"/>
  151. public class ListConverter<T> : CollectionConverter<T, List<T>>
  152. {
  153. /// <summary>
  154. /// Creates an <see cref="ListConverter{T}"/> using the default converter for <typeparamref name="T"/>.
  155. /// </summary>
  156. /// <seealso cref="CollectionConverter{T, TCollection}.CollectionConverter()"/>
  157. public ListConverter() : base() { }
  158. /// <summary>
  159. /// Creates an <see cref="ListConverter{T}"/> using the specified underlying converter for values.
  160. /// </summary>
  161. /// <param name="underlying">the underlying <see cref="ValueConverter{T}"/> to use for the values</param>
  162. public ListConverter(ValueConverter<T> underlying) : base(underlying) { }
  163. /// <summary>
  164. /// Creates a new <see cref="List{T}"/> for deserialization.
  165. /// </summary>
  166. /// <param name="size">the size to initialize it to</param>
  167. /// <param name="parent">the object that will own the new object</param>
  168. /// <returns>the new <see cref="List{T}"/></returns>
  169. protected override List<T> Create(int size, object parent)
  170. => new List<T>(size);
  171. }
  172. /// <summary>
  173. /// A <see cref="ListConverter{T}"/> which default constructs a converter for use as the value converter.
  174. /// </summary>
  175. /// <typeparam name="T">the value type of the collection</typeparam>
  176. /// <typeparam name="TConverter">the type of the converter to use for <typeparamref name="T"/></typeparam>
  177. /// <seealso cref="ListConverter{T}"/>
  178. public sealed class ListConverter<T, TConverter> : ListConverter<T>
  179. where TConverter : ValueConverter<T>, new()
  180. {
  181. /// <summary>
  182. /// Creates an <see cref="ListConverter{T}"/> using a default constructed <typeparamref name="TConverter"/>
  183. /// element type. Equivalent to calling <see cref="ListConverter{T}.ListConverter(ValueConverter{T})"/>
  184. /// with a default-constructed <typeparamref name="TConverter"/>.
  185. /// </summary>
  186. /// <seealso cref="ListConverter{T}.ListConverter(ValueConverter{T})"/>
  187. public ListConverter() : base(new TConverter()) { }
  188. }
  189. /// <summary>
  190. /// A <see cref="CollectionConverter{T, TCollection}"/> for an <see cref="IList{T}"/>, creating a <see cref="List{T}"/> when deserializing.
  191. /// </summary>
  192. /// <typeparam name="T">the element type of the <see cref="IList{T}"/></typeparam>
  193. /// <seealso cref="CollectionConverter{T, TCollection}"/>
  194. public class IListConverter<T> : CollectionConverter<T, IList<T>>
  195. {
  196. /// <summary>
  197. /// Creates an <see cref="IListConverter{T}"/> using the default converter for <typeparamref name="T"/>.
  198. /// </summary>
  199. /// <seealso cref="CollectionConverter{T, TCollection}.CollectionConverter()"/>
  200. public IListConverter() : base() { }
  201. /// <summary>
  202. /// Creates an <see cref="IListConverter{T}"/> using the specified underlying converter for values.
  203. /// </summary>
  204. /// <param name="underlying">the underlying <see cref="ValueConverter{T}"/> to use for the values</param>
  205. public IListConverter(ValueConverter<T> underlying) : base(underlying) { }
  206. /// <summary>
  207. /// Creates a new <see cref="IList{T}"/> (a <see cref="List{T}"/>) for deserialization.
  208. /// </summary>
  209. /// <param name="size">the size to initialize it to</param>
  210. /// <param name="parent">the object that will own the new object</param>
  211. /// <returns>the new <see cref="IList{T}"/></returns>
  212. protected override IList<T> Create(int size, object parent)
  213. => new List<T>(size);
  214. }
  215. /// <summary>
  216. /// An <see cref="IListConverter{T}"/> which default constructs a converter for use as the value converter.
  217. /// </summary>
  218. /// <typeparam name="T">the value type of the collection</typeparam>
  219. /// <typeparam name="TConverter">the type of the converter to use for <typeparamref name="T"/></typeparam>
  220. /// <seealso cref="IListConverter{T}"/>
  221. public sealed class IListConverter<T, TConverter> : IListConverter<T>
  222. where TConverter : ValueConverter<T>, new()
  223. {
  224. /// <summary>
  225. /// Creates an <see cref="IListConverter{T}"/> using a default constructed <typeparamref name="TConverter"/>
  226. /// element type. Equivalent to calling <see cref="IListConverter{T}.IListConverter(ValueConverter{T})"/>
  227. /// with a default-constructed <typeparamref name="TConverter"/>.
  228. /// </summary>
  229. /// <seealso cref="IListConverter{T}.IListConverter(ValueConverter{T})"/>
  230. public IListConverter() : base(new TConverter()) { }
  231. }
  232. }