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