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.

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