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.

643 lines
30 KiB

5 years ago
5 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
5 years ago
5 years ago
  1. using IPA.Config.Data;
  2. using IPA.Config.Stores.Attributes;
  3. using IPA.Logging;
  4. using System;
  5. using System.Collections.Generic;
  6. using System.Linq;
  7. using System.Text;
  8. using System.Threading.Tasks;
  9. using Boolean = IPA.Config.Data.Boolean;
  10. namespace IPA.Config.Stores.Converters
  11. {
  12. /// <summary>
  13. /// Provides utility functions for custom converters.
  14. /// </summary>
  15. public static class Converter
  16. {
  17. /// <summary>
  18. /// Gets the integral value of a <see cref="Value"/>, coercing a <see cref="FloatingPoint"/> if necessary,
  19. /// or <see langword="null"/> if <paramref name="val"/> is not an <see cref="Integer"/> or <see cref="FloatingPoint"/>.
  20. /// </summary>
  21. /// <param name="val">the <see cref="Value"/> to get the integral value of</param>
  22. /// <returns>the integral value of <paramref name="val"/>, or <see langword="null"/></returns>
  23. public static long? IntValue(Value val)
  24. => val is Integer inte ? inte.Value :
  25. val is FloatingPoint fp ? fp.AsInteger()?.Value :
  26. null;
  27. /// <summary>
  28. /// Gets the floaing point value of a <see cref="Value"/>, coercing an <see cref="Integer"/> if necessary,
  29. /// or <see langword="null"/> if <paramref name="val"/> is not an <see cref="Integer"/> or <see cref="FloatingPoint"/>.
  30. /// </summary>
  31. /// <param name="val">the <see cref="Value"/> to get the floaing point value of</param>
  32. /// <returns>the floaing point value of <paramref name="val"/>, or <see langword="null"/></returns>
  33. public static decimal? FloatValue(Value val)
  34. => val is FloatingPoint fp ? fp.Value :
  35. val is Integer inte ? inte.AsFloat()?.Value :
  36. null;
  37. internal static Type GetDefaultConverterType(Type t)
  38. {
  39. if (t.IsEnum)
  40. {
  41. return typeof(CaseInsensitiveEnumConverter<>).MakeGenericType(t);
  42. }
  43. if (t.IsGenericType)
  44. {
  45. var generic = t.GetGenericTypeDefinition();
  46. var args = t.GetGenericArguments();
  47. if (generic == typeof(List<>))
  48. return (typeof(ListConverter<>).MakeGenericType(args));
  49. else if (generic == typeof(IList<>))
  50. return (typeof(IListConverter<>).MakeGenericType(args));
  51. else if (generic == typeof(Dictionary<,>) && args[0] == typeof(string))
  52. return (typeof(DictionaryConverter<>).MakeGenericType(args[1]));
  53. else if (generic == typeof(IDictionary<,>) && args[0] == typeof(string))
  54. return (typeof(IDictionaryConverter<>).MakeGenericType(args[1]));
  55. #if NET4
  56. else if (generic == typeof(ISet<>))
  57. return (typeof(ISetConverter<>).MakeGenericType(args));
  58. else if (generic == typeof(IReadOnlyDictionary<,>) && args[0] == typeof(string))
  59. return (typeof(IReadOnlyDictionaryConverter<>).MakeGenericType(args[1]));
  60. #endif
  61. }
  62. var iCollBase = t.GetInterfaces()
  63. .FirstOrDefault(i => i.IsGenericType && i.GetGenericTypeDefinition() == typeof(ICollection<>));
  64. if (iCollBase != null && t.GetConstructor(Type.EmptyTypes) != null)
  65. { // if it implements ICollection and has a default constructor
  66. var valueType = iCollBase.GetGenericArguments().First();
  67. return (typeof(CollectionConverter<,>).MakeGenericType(valueType, t));
  68. }
  69. if (t == typeof(string))
  70. {
  71. //Logger.log.Debug($"gives StringConverter");
  72. return typeof(StringConverter);
  73. }
  74. if (t.IsValueType)
  75. { // we have to do this garbo to make it accept the thing that we know is a value type at instantiation time
  76. if (t.IsGenericType && t.GetGenericTypeDefinition() == typeof(Nullable<>))
  77. { // this is a Nullable
  78. //Logger.log.Debug($"gives NullableConverter<{Nullable.GetUnderlyingType(t)}>");
  79. return (typeof(NullableConverter<>).MakeGenericType(Nullable.GetUnderlyingType(t)));
  80. }
  81. //Logger.log.Debug($"gives converter for value type {t}");
  82. var valConv = Activator.CreateInstance(typeof(ValConv<>).MakeGenericType(t)) as IValConv;
  83. return valConv.Get();
  84. }
  85. //Logger.log.Debug($"gives CustomObjectConverter<{t}>");
  86. return (typeof(CustomObjectConverter<>).MakeGenericType(t));
  87. }
  88. internal interface IValConv
  89. {
  90. Type Get();
  91. }
  92. internal interface IValConv<T>
  93. {
  94. Type Get();
  95. }
  96. internal class ValConv<T> : IValConv, IValConv<T> where T : struct
  97. {
  98. private static readonly IValConv<T> Impl = ValConvImpls.Impl as IValConv<T> ?? new ValConv<T>();
  99. public Type Get() => Impl.Get();
  100. Type IValConv<T>.Get()
  101. => typeof(CustomValueTypeConverter<T>);
  102. }
  103. private class ValConvImpls : IValConv<char>,
  104. IValConv<IntPtr>, IValConv<UIntPtr>,
  105. IValConv<long>, IValConv<ulong>,
  106. IValConv<int>, IValConv<uint>,
  107. IValConv<short>, IValConv<ushort>,
  108. IValConv<sbyte>, IValConv<byte>,
  109. IValConv<float>, IValConv<double>,
  110. IValConv<decimal>, IValConv<bool>,
  111. IValConv<DateTime>
  112. {
  113. internal static readonly ValConvImpls Impl = new ValConvImpls();
  114. Type IValConv<char>.Get() => typeof(CharConverter);
  115. Type IValConv<long>.Get() => typeof(LongConverter);
  116. Type IValConv<ulong>.Get() => typeof(ULongConverter);
  117. Type IValConv<IntPtr>.Get() => typeof(IntPtrConverter);
  118. Type IValConv<UIntPtr>.Get() => typeof(UIntPtrConverter);
  119. Type IValConv<int>.Get() => typeof(IntConverter);
  120. Type IValConv<uint>.Get() => typeof(UIntConverter);
  121. Type IValConv<short>.Get() => typeof(ShortConverter);
  122. Type IValConv<ushort>.Get() => typeof(UShortConverter);
  123. Type IValConv<byte>.Get() => typeof(ByteConverter);
  124. Type IValConv<sbyte>.Get() => typeof(SByteConverter);
  125. Type IValConv<float>.Get() => typeof(FloatConverter);
  126. Type IValConv<double>.Get() => typeof(DoubleConverter);
  127. Type IValConv<decimal>.Get() => typeof(DecimalConverter);
  128. Type IValConv<bool>.Get() => typeof(BooleanConverter);
  129. Type IValConv<DateTime>.Get() => typeof(DateTimeConverter);
  130. }
  131. }
  132. /// <summary>
  133. /// Provides generic utilities for converters for certain types.
  134. /// </summary>
  135. /// <typeparam name="T">the type of the <see cref="ValueConverter{T}"/> that this works on</typeparam>
  136. public static class Converter<T>
  137. {
  138. private static ValueConverter<T> defaultConverter = null;
  139. /// <summary>
  140. /// Gets the default <see cref="ValueConverter{T}"/> for the current type.
  141. /// </summary>
  142. public static ValueConverter<T> Default
  143. => defaultConverter ??= MakeDefault();
  144. internal static ValueConverter<T> MakeDefault()
  145. {
  146. var t = typeof(T);
  147. //Logger.log.Debug($"Converter<{t}>.MakeDefault()");
  148. static ValueConverter<T> MakeInstOf(Type ty)
  149. => Activator.CreateInstance(ty) as ValueConverter<T>;
  150. return MakeInstOf(Converter.GetDefaultConverterType(t));
  151. }
  152. }
  153. /// <summary>
  154. /// A converter for a <see cref="Nullable{T}"/>.
  155. /// </summary>
  156. /// <typeparam name="T">the underlying type of the <see cref="Nullable{T}"/></typeparam>
  157. public class NullableConverter<T> : ValueConverter<T?> where T : struct
  158. {
  159. private readonly ValueConverter<T> baseConverter;
  160. /// <summary>
  161. /// Creates a converter with the default converter for the base type.
  162. /// Equivalent to
  163. /// <code>
  164. /// new NullableConverter(Converter&lt;T&gt;.Default)
  165. /// </code>
  166. /// </summary>
  167. /// <seealso cref="NullableConverter{T}.NullableConverter(ValueConverter{T})"/>
  168. /// <seealso cref="Converter{T}.Default"/>
  169. public NullableConverter() : this(Converter<T>.Default) { }
  170. /// <summary>
  171. /// Creates a converter with the given underlying <see cref="ValueConverter{T}"/>.
  172. /// </summary>
  173. /// <param name="underlying">the undlerlying <see cref="ValueConverter{T}"/> to use</param>
  174. public NullableConverter(ValueConverter<T> underlying)
  175. => baseConverter = underlying;
  176. /// <summary>
  177. /// Converts a <see cref="Value"/> tree to a value.
  178. /// </summary>
  179. /// <param name="value">the <see cref="Value"/> tree to convert</param>
  180. /// <param name="parent">the object which will own the created object</param>
  181. /// <returns>the object represented by <paramref name="value"/></returns>
  182. public override T? FromValue(Value value, object parent)
  183. => value == null ? null : new T?(baseConverter.FromValue(value, parent));
  184. /// <summary>
  185. /// Converts a nullable <typeparamref name="T"/> to a <see cref="Value"/> tree.
  186. /// </summary>
  187. /// <param name="obj">the value to serialize</param>
  188. /// <param name="parent">the object which owns <paramref name="obj"/></param>
  189. /// <returns>a <see cref="Value"/> tree representing <paramref name="obj"/>.</returns>
  190. public override Value ToValue(T? obj, object parent)
  191. => obj == null ? null : baseConverter.ToValue(obj.Value, parent);
  192. }
  193. /// <summary>
  194. /// A converter for a <see cref="Nullable{T}"/> that default-constructs a converter of type <typeparamref name="TConverter"/>
  195. /// to use as the underlying converter. Use this in the <see cref="UseConverterAttribute"/>.
  196. /// </summary>
  197. /// <typeparam name="T">the underlying type of the <see cref="Nullable{T}"/></typeparam>
  198. /// <typeparam name="TConverter">the type to use as an underlying converter</typeparam>
  199. /// <seealso cref="NullableConverter{T}"/>
  200. public sealed class NullableConverter<T, TConverter> : NullableConverter<T>
  201. where T : struct
  202. where TConverter : ValueConverter<T>, new()
  203. {
  204. /// <summary>
  205. /// Creates a converter with a new <typeparamref name="TConverter"/> as the underlying converter.
  206. /// </summary>
  207. /// <seealso cref="NullableConverter{T}.NullableConverter(ValueConverter{T})"/>
  208. public NullableConverter() : base(new TConverter()) { }
  209. }
  210. /// <summary>
  211. /// A converter for an enum of type <typeparamref name="T"/>, that converts the enum to its string representation and back.
  212. /// </summary>
  213. /// <typeparam name="T">the enum type</typeparam>
  214. public sealed class EnumConverter<T> : ValueConverter<T>
  215. where T : Enum
  216. {
  217. /// <summary>
  218. /// Converts a <see cref="Value"/> that is a <see cref="Text"/> node to the corresponding enum value.
  219. /// </summary>
  220. /// <param name="value">the <see cref="Value"/> to convert</param>
  221. /// <param name="parent">the object which will own the created object</param>
  222. /// <returns>the deserialized enum value</returns>
  223. /// <exception cref="ArgumentException">if <paramref name="value"/> is not a <see cref="Text"/> node</exception>
  224. public override T FromValue(Value value, object parent)
  225. => value is Text t
  226. ? (T)Enum.Parse(typeof(T), t.Value)
  227. : throw new ArgumentException("Value not a string", nameof(value));
  228. /// <summary>
  229. /// Converts an enum of type <typeparamref name="T"/> to a <see cref="Value"/> node corresponding to its value.
  230. /// </summary>
  231. /// <param name="obj">the value to serialize</param>
  232. /// <param name="parent">the object which owns <paramref name="obj"/></param>
  233. /// <returns>a <see cref="Text"/> node representing <paramref name="obj"/></returns>
  234. public override Value ToValue(T obj, object parent)
  235. => Value.Text(obj.ToString());
  236. }
  237. /// <summary>
  238. /// A converter for an enum of type <typeparamref name="T"/>, that converts the enum to its string representation and back,
  239. /// ignoring the case of the serialized value for deseiralization.
  240. /// </summary>
  241. /// <typeparam name="T">the enum type</typeparam>
  242. public sealed class CaseInsensitiveEnumConverter<T> : ValueConverter<T>
  243. where T : Enum
  244. {
  245. /// <summary>
  246. /// Converts a <see cref="Value"/> that is a <see cref="Text"/> node to the corresponding enum value.
  247. /// </summary>
  248. /// <param name="value">the <see cref="Value"/> to convert</param>
  249. /// <param name="parent">the object which will own the created object</param>
  250. /// <returns>the deserialized enum value</returns>
  251. /// <exception cref="ArgumentException">if <paramref name="value"/> is not a <see cref="Text"/> node</exception>
  252. public override T FromValue(Value value, object parent)
  253. => value is Text t
  254. ? (T)Enum.Parse(typeof(T), t.Value, true)
  255. : throw new ArgumentException("Value not a string", nameof(value));
  256. /// <summary>
  257. /// Converts an enum of type <typeparamref name="T"/> to a <see cref="Value"/> node corresponding to its value.
  258. /// </summary>
  259. /// <param name="obj">the value to serialize</param>
  260. /// <param name="parent">the object which owns <paramref name="obj"/></param>
  261. /// <returns>a <see cref="Text"/> node representing <paramref name="obj"/></returns>
  262. public override Value ToValue(T obj, object parent)
  263. => Value.Text(obj.ToString());
  264. }
  265. /// <summary>
  266. /// A converter for an enum of type <typeparamref name="T"/>, that converts the enum to its underlying value for serialization.
  267. /// </summary>
  268. /// <typeparam name="T">the enum type</typeparam>
  269. public sealed class NumericEnumConverter<T> : ValueConverter<T>
  270. where T : Enum
  271. {
  272. /// <summary>
  273. /// Converts a <see cref="Value"/> that is a numeric node to the corresponding enum value.
  274. /// </summary>
  275. /// <param name="value">the <see cref="Value"/> to convert</param>
  276. /// <param name="parent">the object which will own the created object</param>
  277. /// <returns>the deserialized enum value</returns>
  278. /// <exception cref="ArgumentException">if <paramref name="value"/> is not a numeric node</exception>
  279. public override T FromValue(Value value, object parent)
  280. => (T)Enum.ToObject(typeof(T), Converter.IntValue(value)
  281. ?? throw new ArgumentException("Value not a numeric node", nameof(value)));
  282. /// <summary>
  283. /// Converts an enum of type <typeparamref name="T"/> to a <see cref="Value"/> node corresponding to its value.
  284. /// </summary>
  285. /// <param name="obj">the value to serialize</param>
  286. /// <param name="parent">the object which owns <paramref name="obj"/></param>
  287. /// <returns>an <see cref="Integer"/> node representing <paramref name="obj"/></returns>
  288. public override Value ToValue(T obj, object parent)
  289. => Value.Integer(Convert.ToInt64(obj));
  290. }
  291. /// <summary>
  292. /// A converter for instances of <see cref="IDictionary{TKey, TValue}"/>.
  293. /// </summary>
  294. /// <typeparam name="TValue">the value type of the dictionary</typeparam>
  295. public class IDictionaryConverter<TValue> : ValueConverter<IDictionary<string, TValue>>
  296. {
  297. /// <summary>
  298. /// Gets the converter for the dictionary's value type.
  299. /// </summary>
  300. protected ValueConverter<TValue> BaseConverter { get; }
  301. /// <summary>
  302. /// Constructs an <see cref="IDictionaryConverter{TValue}"/> using the default converter for the value type.
  303. /// </summary>
  304. public IDictionaryConverter() : this(Converter<TValue>.Default) { }
  305. /// <summary>
  306. /// Constructs an <see cref="IDictionaryConverter{TValue}"/> using the specified converter for the value.
  307. /// </summary>
  308. /// <param name="converter">the converter for the value</param>
  309. public IDictionaryConverter(ValueConverter<TValue> converter)
  310. => BaseConverter = converter;
  311. /// <summary>
  312. /// Converts a <see cref="Map"/> to an <see cref="IDictionary{TKey, TValue}"/> that is represented by it.
  313. /// </summary>
  314. /// <param name="value">the <see cref="Map"/> to convert</param>
  315. /// <param name="parent">the parent that will own the resulting object</param>
  316. /// <returns>the deserialized dictionary</returns>
  317. public override IDictionary<string, TValue> FromValue(Value value, object parent)
  318. => (value as Map)?.Select(kvp => (kvp.Key, val: BaseConverter.FromValue(kvp.Value, parent)))
  319. ?.ToDictionary(p => p.Key, p => p.val)
  320. ?? throw new ArgumentException("Value not a map", nameof(value));
  321. /// <summary>
  322. /// Serializes an <see cref="IDictionary{TKey, TValue}"/> into a <see cref="Map"/> containing its values.
  323. /// </summary>
  324. /// <param name="obj">the dictionary to serialize</param>
  325. /// <param name="parent">the object that owns the dictionary</param>
  326. /// <returns>the dictionary serialized as a <see cref="Map"/></returns>
  327. public override Value ToValue(IDictionary<string, TValue> obj, object parent)
  328. => Value.From(obj.Select(p => new KeyValuePair<string, Value>(p.Key, BaseConverter.ToValue(p.Value, parent))));
  329. }
  330. /// <summary>
  331. /// A converter for instances of <see cref="IDictionary{TKey, TValue}"/>, specifying a value converter as a type parameter.
  332. /// </summary>
  333. /// <typeparam name="TValue">the value type of the dictionary</typeparam>
  334. /// <typeparam name="TConverter">the converter type for values</typeparam>
  335. public sealed class IDictionaryConverter<TValue, TConverter> : IDictionaryConverter<TValue>
  336. where TConverter : ValueConverter<TValue>, new()
  337. {
  338. /// <summary>
  339. /// Constructs a new <see cref="IDictionaryConverter{TValue, TConverter}"/> with a new instance of
  340. /// <typeparamref name="TConverter"/> as the value converter.
  341. /// </summary>
  342. public IDictionaryConverter() : base(new TConverter()) { }
  343. }
  344. /// <summary>
  345. /// A converter for instances of <see cref="Dictionary{TKey, TValue}"/>.
  346. /// </summary>
  347. /// <typeparam name="TValue">the value type of the dictionary</typeparam>
  348. public class DictionaryConverter<TValue> : ValueConverter<Dictionary<string, TValue>>
  349. {
  350. /// <summary>
  351. /// Gets the converter for the dictionary's value type.
  352. /// </summary>
  353. protected ValueConverter<TValue> BaseConverter { get; }
  354. /// <summary>
  355. /// Constructs an <see cref="IDictionaryConverter{TValue}"/> using the default converter for the value type.
  356. /// </summary>
  357. public DictionaryConverter() : this(Converter<TValue>.Default) { }
  358. /// <summary>
  359. /// Constructs an <see cref="IDictionaryConverter{TValue}"/> using the specified converter for the value.
  360. /// </summary>
  361. /// <param name="converter">the converter for the value</param>
  362. public DictionaryConverter(ValueConverter<TValue> converter)
  363. => BaseConverter = converter;
  364. /// <summary>
  365. /// Converts a <see cref="Map"/> to a <see cref="Dictionary{TKey, TValue}"/> that is represented by it.
  366. /// </summary>
  367. /// <param name="value">the <see cref="Map"/> to convert</param>
  368. /// <param name="parent">the parent that will own the resulting object</param>
  369. /// <returns>the deserialized dictionary</returns>
  370. public override Dictionary<string, TValue> FromValue(Value value, object parent)
  371. => (value as Map)?.Select(kvp => (kvp.Key, val: BaseConverter.FromValue(kvp.Value, parent)))
  372. ?.ToDictionary(p => p.Key, p => p.val)
  373. ?? throw new ArgumentException("Value not a map", nameof(value));
  374. /// <summary>
  375. /// Serializes a <see cref="Dictionary{TKey, TValue}"/> into a <see cref="Map"/> containing its values.
  376. /// </summary>
  377. /// <param name="obj">the dictionary to serialize</param>
  378. /// <param name="parent">the object that owns the dictionary</param>
  379. /// <returns>the dictionary serialized as a <see cref="Map"/></returns>
  380. public override Value ToValue(Dictionary<string, TValue> obj, object parent)
  381. => Value.From(obj.Select(p => new KeyValuePair<string, Value>(p.Key, BaseConverter.ToValue(p.Value, parent))));
  382. }
  383. /// <summary>
  384. /// A converter for instances of <see cref="Dictionary{TKey, TValue}"/>, specifying a value converter as a type parameter.
  385. /// </summary>
  386. /// <typeparam name="TValue">the value type of the dictionary</typeparam>
  387. /// <typeparam name="TConverter">the converter type for values</typeparam>
  388. public sealed class DictionaryConverter<TValue, TConverter> : DictionaryConverter<TValue>
  389. where TConverter : ValueConverter<TValue>, new()
  390. {
  391. /// <summary>
  392. /// Constructs a new <see cref="IDictionaryConverter{TValue, TConverter}"/> with a new instance of
  393. /// <typeparamref name="TConverter"/> as the value converter.
  394. /// </summary>
  395. public DictionaryConverter() : base(new TConverter()) { }
  396. }
  397. #if NET4
  398. /// <summary>
  399. /// A converter for instances of <see cref="IReadOnlyDictionary{TKey, TValue}"/>.
  400. /// </summary>
  401. /// <typeparam name="TValue">the value type of the dictionary</typeparam>
  402. public class IReadOnlyDictionaryConverter<TValue> : ValueConverter<IReadOnlyDictionary<string, TValue>>
  403. {
  404. /// <summary>
  405. /// Gets the converter for the dictionary's value type.
  406. /// </summary>
  407. protected ValueConverter<TValue> BaseConverter { get; }
  408. /// <summary>
  409. /// Constructs an <see cref="IReadOnlyDictionaryConverter{TValue}"/> using the default converter for the value type.
  410. /// </summary>
  411. public IReadOnlyDictionaryConverter() : this(Converter<TValue>.Default) { }
  412. /// <summary>
  413. /// Constructs an <see cref="IReadOnlyDictionaryConverter{TValue}"/> using the specified converter for the value.
  414. /// </summary>
  415. /// <param name="converter">the converter for the value</param>
  416. public IReadOnlyDictionaryConverter(ValueConverter<TValue> converter)
  417. => BaseConverter = converter;
  418. /// <summary>
  419. /// Converts a <see cref="Map"/> to an <see cref="IDictionary{TKey, TValue}"/> that is represented by it.
  420. /// </summary>
  421. /// <param name="value">the <see cref="Map"/> to convert</param>
  422. /// <param name="parent">the parent that will own the resulting object</param>
  423. /// <returns>the deserialized dictionary</returns>
  424. public override IReadOnlyDictionary<string, TValue> FromValue(Value value, object parent)
  425. => (value as Map)?.Select(kvp => (kvp.Key, val: BaseConverter.FromValue(kvp.Value, parent)))
  426. ?.ToDictionary(p => p.Key, p => p.val)
  427. ?? throw new ArgumentException("Value not a map", nameof(value));
  428. /// <summary>
  429. /// Serializes an <see cref="IDictionary{TKey, TValue}"/> into a <see cref="Map"/> containing its values.
  430. /// </summary>
  431. /// <param name="obj">the dictionary to serialize</param>
  432. /// <param name="parent">the object that owns the dictionary</param>
  433. /// <returns>the dictionary serialized as a <see cref="Map"/></returns>
  434. public override Value ToValue(IReadOnlyDictionary<string, TValue> obj, object parent)
  435. => Value.From(obj.Select(p => new KeyValuePair<string, Value>(p.Key, BaseConverter.ToValue(p.Value, parent))));
  436. }
  437. /// <summary>
  438. /// A converter for instances of <see cref="IReadOnlyDictionary{TKey, TValue}"/>, specifying a value converter as a type parameter.
  439. /// </summary>
  440. /// <typeparam name="TValue">the value type of the dictionary</typeparam>
  441. /// <typeparam name="TConverter">the converter type for values</typeparam>
  442. public sealed class IReadOnlyDictionaryConverter<TValue, TConverter> : IReadOnlyDictionaryConverter<TValue>
  443. where TConverter : ValueConverter<TValue>, new()
  444. {
  445. /// <summary>
  446. /// Constructs a new <see cref="IReadOnlyDictionaryConverter{TValue, TConverter}"/> with a new instance of
  447. /// <typeparamref name="TConverter"/> as the value converter.
  448. /// </summary>
  449. public IReadOnlyDictionaryConverter() : base(new TConverter()) { }
  450. }
  451. #endif
  452. internal class StringConverter : ValueConverter<string>
  453. {
  454. public override string FromValue(Value value, object parent)
  455. => (value as Text)?.Value;
  456. public override Value ToValue(string obj, object parent)
  457. => Value.From(obj);
  458. }
  459. internal class CharConverter : ValueConverter<char>
  460. {
  461. public override char FromValue(Value value, object parent)
  462. => (value as Text)?.Value[0]
  463. ?? throw new ArgumentException("Value not a text node", nameof(value)); // can throw nullptr
  464. public override Value ToValue(char obj, object parent)
  465. => Value.From(char.ToString(obj));
  466. }
  467. internal class LongConverter : ValueConverter<long>
  468. {
  469. public override long FromValue(Value value, object parent)
  470. => Converter.IntValue(value)
  471. ?? throw new ArgumentException("Value not a numeric value", nameof(value));
  472. public override Value ToValue(long obj, object parent)
  473. => Value.From(obj);
  474. }
  475. internal class ULongConverter : ValueConverter<ulong>
  476. {
  477. public override ulong FromValue(Value value, object parent)
  478. => (ulong)(Converter.FloatValue(value)
  479. ?? throw new ArgumentException("Value not a numeric value", nameof(value)));
  480. public override Value ToValue(ulong obj, object parent)
  481. => Value.From(obj);
  482. }
  483. internal class IntPtrConverter : ValueConverter<IntPtr>
  484. {
  485. public override IntPtr FromValue(Value value, object parent)
  486. => (IntPtr)Converter<long>.Default.FromValue(value, parent);
  487. public override Value ToValue(IntPtr obj, object parent)
  488. => Value.From((long)obj);
  489. }
  490. internal class UIntPtrConverter : ValueConverter<UIntPtr>
  491. {
  492. public override UIntPtr FromValue(Value value, object parent)
  493. => (UIntPtr)Converter<ulong>.Default.FromValue(value, parent);
  494. public override Value ToValue(UIntPtr obj, object parent)
  495. => Value.From((decimal)obj);
  496. }
  497. internal class IntConverter : ValueConverter<int>
  498. {
  499. public override int FromValue(Value value, object parent)
  500. => (int)Converter<long>.Default.FromValue(value, parent);
  501. public override Value ToValue(int obj, object parent)
  502. => Value.From(obj);
  503. }
  504. internal class UIntConverter : ValueConverter<uint>
  505. {
  506. public override uint FromValue(Value value, object parent)
  507. => (uint)Converter<long>.Default.FromValue(value, parent);
  508. public override Value ToValue(uint obj, object parent)
  509. => Value.From(obj);
  510. }
  511. internal class ShortConverter : ValueConverter<short>
  512. {
  513. public override short FromValue(Value value, object parent)
  514. => (short)Converter<long>.Default.FromValue(value, parent);
  515. public override Value ToValue(short obj, object parent)
  516. => Value.From(obj);
  517. }
  518. internal class UShortConverter : ValueConverter<ushort>
  519. {
  520. public override ushort FromValue(Value value, object parent)
  521. => (ushort)Converter<long>.Default.FromValue(value, parent);
  522. public override Value ToValue(ushort obj, object parent)
  523. => Value.From(obj);
  524. }
  525. internal class ByteConverter : ValueConverter<byte>
  526. {
  527. public override byte FromValue(Value value, object parent)
  528. => (byte)Converter<long>.Default.FromValue(value, parent);
  529. public override Value ToValue(byte obj, object parent)
  530. => Value.From(obj);
  531. }
  532. internal class SByteConverter : ValueConverter<sbyte>
  533. {
  534. public override sbyte FromValue(Value value, object parent)
  535. => (sbyte)Converter<long>.Default.FromValue(value, parent);
  536. public override Value ToValue(sbyte obj, object parent)
  537. => Value.From(obj);
  538. }
  539. internal class DecimalConverter : ValueConverter<decimal>
  540. {
  541. public override decimal FromValue(Value value, object parent)
  542. => Converter.FloatValue(value) ?? throw new ArgumentException("Value not a numeric value", nameof(value));
  543. public override Value ToValue(decimal obj, object parent)
  544. => Value.From(obj);
  545. }
  546. internal class FloatConverter : ValueConverter<float>
  547. {
  548. public override float FromValue(Value value, object parent)
  549. => (float)Converter<decimal>.Default.FromValue(value, parent);
  550. public override Value ToValue(float obj, object parent)
  551. => Value.From((decimal)obj);
  552. }
  553. internal class DoubleConverter : ValueConverter<double>
  554. {
  555. public override double FromValue(Value value, object parent)
  556. => (double)Converter<decimal>.Default.FromValue(value, parent);
  557. public override Value ToValue(double obj, object parent)
  558. => Value.From((decimal)obj);
  559. }
  560. internal class BooleanConverter : ValueConverter<bool>
  561. {
  562. public override bool FromValue(Value value, object parent)
  563. => (value as Boolean)?.Value ?? throw new ArgumentException("Value not a Boolean", nameof(value));
  564. public override Value ToValue(bool obj, object parent)
  565. => Value.From(obj);
  566. }
  567. internal class DateTimeConverter : ValueConverter<DateTime>
  568. {
  569. public override DateTime FromValue(Value value, object parent)
  570. {
  571. if (!(value is Text text))
  572. {
  573. throw new ArgumentException("Value is not of type Text", nameof(value));
  574. }
  575. if (DateTime.TryParse(text.Value, out var dateTime))
  576. {
  577. return dateTime;
  578. }
  579. throw new ArgumentException($"Parsing failed, {text.Value}");
  580. }
  581. public override Value ToValue(DateTime obj, object parent) => Value.Text(obj.ToString("O"));
  582. }
  583. }