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.

621 lines
30 KiB

4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 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. {
  112. internal static readonly ValConvImpls Impl = new ValConvImpls();
  113. Type IValConv<char>.Get() => typeof(CharConverter);
  114. Type IValConv<long>.Get() => typeof(LongConverter);
  115. Type IValConv<ulong>.Get() => typeof(ULongConverter);
  116. Type IValConv<IntPtr>.Get() => typeof(IntPtrConverter);
  117. Type IValConv<UIntPtr>.Get() => typeof(UIntPtrConverter);
  118. Type IValConv<int>.Get() => typeof(IntConverter);
  119. Type IValConv<uint>.Get() => typeof(UIntConverter);
  120. Type IValConv<short>.Get() => typeof(ShortConverter);
  121. Type IValConv<ushort>.Get() => typeof(UShortConverter);
  122. Type IValConv<byte>.Get() => typeof(ByteConverter);
  123. Type IValConv<sbyte>.Get() => typeof(SByteConverter);
  124. Type IValConv<float>.Get() => typeof(FloatConverter);
  125. Type IValConv<double>.Get() => typeof(DoubleConverter);
  126. Type IValConv<decimal>.Get() => typeof(DecimalConverter);
  127. Type IValConv<bool>.Get() => typeof(BooleanConverter);
  128. }
  129. }
  130. /// <summary>
  131. /// Provides generic utilities for converters for certain types.
  132. /// </summary>
  133. /// <typeparam name="T">the type of the <see cref="ValueConverter{T}"/> that this works on</typeparam>
  134. public static class Converter<T>
  135. {
  136. private static ValueConverter<T> defaultConverter = null;
  137. /// <summary>
  138. /// Gets the default <see cref="ValueConverter{T}"/> for the current type.
  139. /// </summary>
  140. public static ValueConverter<T> Default
  141. => defaultConverter ??= MakeDefault();
  142. internal static ValueConverter<T> MakeDefault()
  143. {
  144. var t = typeof(T);
  145. //Logger.log.Debug($"Converter<{t}>.MakeDefault()");
  146. static ValueConverter<T> MakeInstOf(Type ty)
  147. => Activator.CreateInstance(ty) as ValueConverter<T>;
  148. return MakeInstOf(Converter.GetDefaultConverterType(t));
  149. }
  150. }
  151. /// <summary>
  152. /// A converter for a <see cref="Nullable{T}"/>.
  153. /// </summary>
  154. /// <typeparam name="T">the underlying type of the <see cref="Nullable{T}"/></typeparam>
  155. public class NullableConverter<T> : ValueConverter<T?> where T : struct
  156. {
  157. private readonly ValueConverter<T> baseConverter;
  158. /// <summary>
  159. /// Creates a converter with the default converter for the base type.
  160. /// Equivalent to
  161. /// <code>
  162. /// new NullableConverter(Converter&lt;T&gt;.Default)
  163. /// </code>
  164. /// </summary>
  165. /// <seealso cref="NullableConverter{T}.NullableConverter(ValueConverter{T})"/>
  166. /// <seealso cref="Converter{T}.Default"/>
  167. public NullableConverter() : this(Converter<T>.Default) { }
  168. /// <summary>
  169. /// Creates a converter with the given underlying <see cref="ValueConverter{T}"/>.
  170. /// </summary>
  171. /// <param name="underlying">the undlerlying <see cref="ValueConverter{T}"/> to use</param>
  172. public NullableConverter(ValueConverter<T> underlying)
  173. => baseConverter = underlying;
  174. /// <summary>
  175. /// Converts a <see cref="Value"/> tree to a value.
  176. /// </summary>
  177. /// <param name="value">the <see cref="Value"/> tree to convert</param>
  178. /// <param name="parent">the object which will own the created object</param>
  179. /// <returns>the object represented by <paramref name="value"/></returns>
  180. public override T? FromValue(Value value, object parent)
  181. => value == null ? null : new T?(baseConverter.FromValue(value, parent));
  182. /// <summary>
  183. /// Converts a nullable <typeparamref name="T"/> to a <see cref="Value"/> tree.
  184. /// </summary>
  185. /// <param name="obj">the value to serialize</param>
  186. /// <param name="parent">the object which owns <paramref name="obj"/></param>
  187. /// <returns>a <see cref="Value"/> tree representing <paramref name="obj"/>.</returns>
  188. public override Value ToValue(T? obj, object parent)
  189. => obj == null ? null : baseConverter.ToValue(obj.Value, parent);
  190. }
  191. /// <summary>
  192. /// A converter for a <see cref="Nullable{T}"/> that default-constructs a converter of type <typeparamref name="TConverter"/>
  193. /// to use as the underlying converter. Use this in the <see cref="UseConverterAttribute"/>.
  194. /// </summary>
  195. /// <typeparam name="T">the underlying type of the <see cref="Nullable{T}"/></typeparam>
  196. /// <typeparam name="TConverter">the type to use as an underlying converter</typeparam>
  197. /// <seealso cref="NullableConverter{T}"/>
  198. public sealed class NullableConverter<T, TConverter> : NullableConverter<T>
  199. where T : struct
  200. where TConverter : ValueConverter<T>, new()
  201. {
  202. /// <summary>
  203. /// Creates a converter with a new <typeparamref name="TConverter"/> as the underlying converter.
  204. /// </summary>
  205. /// <seealso cref="NullableConverter{T}.NullableConverter(ValueConverter{T})"/>
  206. public NullableConverter() : base(new TConverter()) { }
  207. }
  208. /// <summary>
  209. /// A converter for an enum of type <typeparamref name="T"/>, that converts the enum to its string representation and back.
  210. /// </summary>
  211. /// <typeparam name="T">the enum type</typeparam>
  212. public sealed class EnumConverter<T> : ValueConverter<T>
  213. where T : Enum
  214. {
  215. /// <summary>
  216. /// Converts a <see cref="Value"/> that is a <see cref="Text"/> node to the corresponding enum value.
  217. /// </summary>
  218. /// <param name="value">the <see cref="Value"/> to convert</param>
  219. /// <param name="parent">the object which will own the created object</param>
  220. /// <returns>the deserialized enum value</returns>
  221. /// <exception cref="ArgumentException">if <paramref name="value"/> is not a <see cref="Text"/> node</exception>
  222. public override T FromValue(Value value, object parent)
  223. => value is Text t
  224. ? (T)Enum.Parse(typeof(T), t.Value)
  225. : throw new ArgumentException("Value not a string", nameof(value));
  226. /// <summary>
  227. /// Converts an enum of type <typeparamref name="T"/> to a <see cref="Value"/> node corresponding to its value.
  228. /// </summary>
  229. /// <param name="obj">the value to serialize</param>
  230. /// <param name="parent">the object which owns <paramref name="obj"/></param>
  231. /// <returns>a <see cref="Text"/> node representing <paramref name="obj"/></returns>
  232. public override Value ToValue(T obj, object parent)
  233. => Value.Text(obj.ToString());
  234. }
  235. /// <summary>
  236. /// A converter for an enum of type <typeparamref name="T"/>, that converts the enum to its string representation and back,
  237. /// ignoring the case of the serialized value for deseiralization.
  238. /// </summary>
  239. /// <typeparam name="T">the enum type</typeparam>
  240. public sealed class CaseInsensitiveEnumConverter<T> : ValueConverter<T>
  241. where T : Enum
  242. {
  243. /// <summary>
  244. /// Converts a <see cref="Value"/> that is a <see cref="Text"/> node to the corresponding enum value.
  245. /// </summary>
  246. /// <param name="value">the <see cref="Value"/> to convert</param>
  247. /// <param name="parent">the object which will own the created object</param>
  248. /// <returns>the deserialized enum value</returns>
  249. /// <exception cref="ArgumentException">if <paramref name="value"/> is not a <see cref="Text"/> node</exception>
  250. public override T FromValue(Value value, object parent)
  251. => value is Text t
  252. ? (T)Enum.Parse(typeof(T), t.Value, true)
  253. : throw new ArgumentException("Value not a string", nameof(value));
  254. /// <summary>
  255. /// Converts an enum of type <typeparamref name="T"/> to a <see cref="Value"/> node corresponding to its value.
  256. /// </summary>
  257. /// <param name="obj">the value to serialize</param>
  258. /// <param name="parent">the object which owns <paramref name="obj"/></param>
  259. /// <returns>a <see cref="Text"/> node representing <paramref name="obj"/></returns>
  260. public override Value ToValue(T obj, object parent)
  261. => Value.Text(obj.ToString());
  262. }
  263. /// <summary>
  264. /// A converter for an enum of type <typeparamref name="T"/>, that converts the enum to its underlying value for serialization.
  265. /// </summary>
  266. /// <typeparam name="T">the enum type</typeparam>
  267. public sealed class NumericEnumConverter<T> : ValueConverter<T>
  268. where T : Enum
  269. {
  270. /// <summary>
  271. /// Converts a <see cref="Value"/> that is a numeric node to the corresponding enum value.
  272. /// </summary>
  273. /// <param name="value">the <see cref="Value"/> to convert</param>
  274. /// <param name="parent">the object which will own the created object</param>
  275. /// <returns>the deserialized enum value</returns>
  276. /// <exception cref="ArgumentException">if <paramref name="value"/> is not a numeric node</exception>
  277. public override T FromValue(Value value, object parent)
  278. => (T)Enum.ToObject(typeof(T), Converter.IntValue(value)
  279. ?? throw new ArgumentException("Value not a numeric node", nameof(value)));
  280. /// <summary>
  281. /// Converts an enum of type <typeparamref name="T"/> to a <see cref="Value"/> node corresponding to its value.
  282. /// </summary>
  283. /// <param name="obj">the value to serialize</param>
  284. /// <param name="parent">the object which owns <paramref name="obj"/></param>
  285. /// <returns>an <see cref="Integer"/> node representing <paramref name="obj"/></returns>
  286. public override Value ToValue(T obj, object parent)
  287. => Value.Integer(Convert.ToInt64(obj));
  288. }
  289. /// <summary>
  290. /// A converter for instances of <see cref="IDictionary{TKey, TValue}"/>.
  291. /// </summary>
  292. /// <typeparam name="TValue">the value type of the dictionary</typeparam>
  293. public class IDictionaryConverter<TValue> : ValueConverter<IDictionary<string, TValue>>
  294. {
  295. /// <summary>
  296. /// Gets the converter for the dictionary's value type.
  297. /// </summary>
  298. protected ValueConverter<TValue> BaseConverter { get; }
  299. /// <summary>
  300. /// Constructs an <see cref="IDictionaryConverter{TValue}"/> using the default converter for the value type.
  301. /// </summary>
  302. public IDictionaryConverter() : this(Converter<TValue>.Default) { }
  303. /// <summary>
  304. /// Constructs an <see cref="IDictionaryConverter{TValue}"/> using the specified converter for the value.
  305. /// </summary>
  306. /// <param name="converter">the converter for the value</param>
  307. public IDictionaryConverter(ValueConverter<TValue> converter)
  308. => BaseConverter = converter;
  309. /// <summary>
  310. /// Converts a <see cref="Map"/> to an <see cref="IDictionary{TKey, TValue}"/> that is represented by it.
  311. /// </summary>
  312. /// <param name="value">the <see cref="Map"/> to convert</param>
  313. /// <param name="parent">the parent that will own the resulting object</param>
  314. /// <returns>the deserialized dictionary</returns>
  315. public override IDictionary<string, TValue> FromValue(Value value, object parent)
  316. => (value as Map)?.Select(kvp => (kvp.Key, val: BaseConverter.FromValue(kvp.Value, parent)))
  317. ?.ToDictionary(p => p.Key, p => p.val)
  318. ?? throw new ArgumentException("Value not a map", nameof(value));
  319. /// <summary>
  320. /// Serializes an <see cref="IDictionary{TKey, TValue}"/> into a <see cref="Map"/> containing its values.
  321. /// </summary>
  322. /// <param name="obj">the dictionary to serialize</param>
  323. /// <param name="parent">the object that owns the dictionary</param>
  324. /// <returns>the dictionary serialized as a <see cref="Map"/></returns>
  325. public override Value ToValue(IDictionary<string, TValue> obj, object parent)
  326. => Value.From(obj.Select(p => new KeyValuePair<string, Value>(p.Key, BaseConverter.ToValue(p.Value, parent))));
  327. }
  328. /// <summary>
  329. /// A converter for instances of <see cref="IDictionary{TKey, TValue}"/>, specifying a value converter as a type parameter.
  330. /// </summary>
  331. /// <typeparam name="TValue">the value type of the dictionary</typeparam>
  332. /// <typeparam name="TConverter">the converter type for values</typeparam>
  333. public sealed class IDictionaryConverter<TValue, TConverter> : IDictionaryConverter<TValue>
  334. where TConverter : ValueConverter<TValue>, new()
  335. {
  336. /// <summary>
  337. /// Constructs a new <see cref="IDictionaryConverter{TValue, TConverter}"/> with a new instance of
  338. /// <typeparamref name="TConverter"/> as the value converter.
  339. /// </summary>
  340. public IDictionaryConverter() : base(new TConverter()) { }
  341. }
  342. /// <summary>
  343. /// A converter for instances of <see cref="Dictionary{TKey, TValue}"/>.
  344. /// </summary>
  345. /// <typeparam name="TValue">the value type of the dictionary</typeparam>
  346. public class DictionaryConverter<TValue> : ValueConverter<Dictionary<string, TValue>>
  347. {
  348. /// <summary>
  349. /// Gets the converter for the dictionary's value type.
  350. /// </summary>
  351. protected ValueConverter<TValue> BaseConverter { get; }
  352. /// <summary>
  353. /// Constructs an <see cref="IDictionaryConverter{TValue}"/> using the default converter for the value type.
  354. /// </summary>
  355. public DictionaryConverter() : this(Converter<TValue>.Default) { }
  356. /// <summary>
  357. /// Constructs an <see cref="IDictionaryConverter{TValue}"/> using the specified converter for the value.
  358. /// </summary>
  359. /// <param name="converter">the converter for the value</param>
  360. public DictionaryConverter(ValueConverter<TValue> converter)
  361. => BaseConverter = converter;
  362. /// <summary>
  363. /// Converts a <see cref="Map"/> to a <see cref="Dictionary{TKey, TValue}"/> that is represented by it.
  364. /// </summary>
  365. /// <param name="value">the <see cref="Map"/> to convert</param>
  366. /// <param name="parent">the parent that will own the resulting object</param>
  367. /// <returns>the deserialized dictionary</returns>
  368. public override Dictionary<string, TValue> FromValue(Value value, object parent)
  369. => (value as Map)?.Select(kvp => (kvp.Key, val: BaseConverter.FromValue(kvp.Value, parent)))
  370. ?.ToDictionary(p => p.Key, p => p.val)
  371. ?? throw new ArgumentException("Value not a map", nameof(value));
  372. /// <summary>
  373. /// Serializes a <see cref="Dictionary{TKey, TValue}"/> into a <see cref="Map"/> containing its values.
  374. /// </summary>
  375. /// <param name="obj">the dictionary to serialize</param>
  376. /// <param name="parent">the object that owns the dictionary</param>
  377. /// <returns>the dictionary serialized as a <see cref="Map"/></returns>
  378. public override Value ToValue(Dictionary<string, TValue> obj, object parent)
  379. => Value.From(obj.Select(p => new KeyValuePair<string, Value>(p.Key, BaseConverter.ToValue(p.Value, parent))));
  380. }
  381. /// <summary>
  382. /// A converter for instances of <see cref="Dictionary{TKey, TValue}"/>, specifying a value converter as a type parameter.
  383. /// </summary>
  384. /// <typeparam name="TValue">the value type of the dictionary</typeparam>
  385. /// <typeparam name="TConverter">the converter type for values</typeparam>
  386. public sealed class DictionaryConverter<TValue, TConverter> : DictionaryConverter<TValue>
  387. where TConverter : ValueConverter<TValue>, new()
  388. {
  389. /// <summary>
  390. /// Constructs a new <see cref="IDictionaryConverter{TValue, TConverter}"/> with a new instance of
  391. /// <typeparamref name="TConverter"/> as the value converter.
  392. /// </summary>
  393. public DictionaryConverter() : base(new TConverter()) { }
  394. }
  395. #if NET4
  396. /// <summary>
  397. /// A converter for instances of <see cref="IReadOnlyDictionary{TKey, TValue}"/>.
  398. /// </summary>
  399. /// <typeparam name="TValue">the value type of the dictionary</typeparam>
  400. public class IReadOnlyDictionaryConverter<TValue> : ValueConverter<IReadOnlyDictionary<string, TValue>>
  401. {
  402. /// <summary>
  403. /// Gets the converter for the dictionary's value type.
  404. /// </summary>
  405. protected ValueConverter<TValue> BaseConverter { get; }
  406. /// <summary>
  407. /// Constructs an <see cref="IReadOnlyDictionaryConverter{TValue}"/> using the default converter for the value type.
  408. /// </summary>
  409. public IReadOnlyDictionaryConverter() : this(Converter<TValue>.Default) { }
  410. /// <summary>
  411. /// Constructs an <see cref="IReadOnlyDictionaryConverter{TValue}"/> using the specified converter for the value.
  412. /// </summary>
  413. /// <param name="converter">the converter for the value</param>
  414. public IReadOnlyDictionaryConverter(ValueConverter<TValue> converter)
  415. => BaseConverter = converter;
  416. /// <summary>
  417. /// Converts a <see cref="Map"/> to an <see cref="IDictionary{TKey, TValue}"/> that is represented by it.
  418. /// </summary>
  419. /// <param name="value">the <see cref="Map"/> to convert</param>
  420. /// <param name="parent">the parent that will own the resulting object</param>
  421. /// <returns>the deserialized dictionary</returns>
  422. public override IReadOnlyDictionary<string, TValue> FromValue(Value value, object parent)
  423. => (value as Map)?.Select(kvp => (kvp.Key, val: BaseConverter.FromValue(kvp.Value, parent)))
  424. ?.ToDictionary(p => p.Key, p => p.val)
  425. ?? throw new ArgumentException("Value not a map", nameof(value));
  426. /// <summary>
  427. /// Serializes an <see cref="IDictionary{TKey, TValue}"/> into a <see cref="Map"/> containing its values.
  428. /// </summary>
  429. /// <param name="obj">the dictionary to serialize</param>
  430. /// <param name="parent">the object that owns the dictionary</param>
  431. /// <returns>the dictionary serialized as a <see cref="Map"/></returns>
  432. public override Value ToValue(IReadOnlyDictionary<string, TValue> obj, object parent)
  433. => Value.From(obj.Select(p => new KeyValuePair<string, Value>(p.Key, BaseConverter.ToValue(p.Value, parent))));
  434. }
  435. /// <summary>
  436. /// A converter for instances of <see cref="IReadOnlyDictionary{TKey, TValue}"/>, specifying a value converter as a type parameter.
  437. /// </summary>
  438. /// <typeparam name="TValue">the value type of the dictionary</typeparam>
  439. /// <typeparam name="TConverter">the converter type for values</typeparam>
  440. public sealed class IReadOnlyDictionaryConverter<TValue, TConverter> : IReadOnlyDictionaryConverter<TValue>
  441. where TConverter : ValueConverter<TValue>, new()
  442. {
  443. /// <summary>
  444. /// Constructs a new <see cref="IReadOnlyDictionaryConverter{TValue, TConverter}"/> with a new instance of
  445. /// <typeparamref name="TConverter"/> as the value converter.
  446. /// </summary>
  447. public IReadOnlyDictionaryConverter() : base(new TConverter()) { }
  448. }
  449. #endif
  450. internal class StringConverter : ValueConverter<string>
  451. {
  452. public override string FromValue(Value value, object parent)
  453. => (value as Text)?.Value;
  454. public override Value ToValue(string obj, object parent)
  455. => Value.From(obj);
  456. }
  457. internal class CharConverter : ValueConverter<char>
  458. {
  459. public override char FromValue(Value value, object parent)
  460. => (value as Text)?.Value[0]
  461. ?? throw new ArgumentException("Value not a text node", nameof(value)); // can throw nullptr
  462. public override Value ToValue(char obj, object parent)
  463. => Value.From(char.ToString(obj));
  464. }
  465. internal class LongConverter : ValueConverter<long>
  466. {
  467. public override long FromValue(Value value, object parent)
  468. => Converter.IntValue(value)
  469. ?? throw new ArgumentException("Value not a numeric value", nameof(value));
  470. public override Value ToValue(long obj, object parent)
  471. => Value.From(obj);
  472. }
  473. internal class ULongConverter : ValueConverter<ulong>
  474. {
  475. public override ulong FromValue(Value value, object parent)
  476. => (ulong)(Converter.FloatValue(value)
  477. ?? throw new ArgumentException("Value not a numeric value", nameof(value)));
  478. public override Value ToValue(ulong obj, object parent)
  479. => Value.From(obj);
  480. }
  481. internal class IntPtrConverter : ValueConverter<IntPtr>
  482. {
  483. public override IntPtr FromValue(Value value, object parent)
  484. => (IntPtr)Converter<long>.Default.FromValue(value, parent);
  485. public override Value ToValue(IntPtr obj, object parent)
  486. => Value.From((long)obj);
  487. }
  488. internal class UIntPtrConverter : ValueConverter<UIntPtr>
  489. {
  490. public override UIntPtr FromValue(Value value, object parent)
  491. => (UIntPtr)Converter<ulong>.Default.FromValue(value, parent);
  492. public override Value ToValue(UIntPtr obj, object parent)
  493. => Value.From((decimal)obj);
  494. }
  495. internal class IntConverter : ValueConverter<int>
  496. {
  497. public override int FromValue(Value value, object parent)
  498. => (int)Converter<long>.Default.FromValue(value, parent);
  499. public override Value ToValue(int obj, object parent)
  500. => Value.From(obj);
  501. }
  502. internal class UIntConverter : ValueConverter<uint>
  503. {
  504. public override uint FromValue(Value value, object parent)
  505. => (uint)Converter<long>.Default.FromValue(value, parent);
  506. public override Value ToValue(uint obj, object parent)
  507. => Value.From(obj);
  508. }
  509. internal class ShortConverter : ValueConverter<short>
  510. {
  511. public override short FromValue(Value value, object parent)
  512. => (short)Converter<long>.Default.FromValue(value, parent);
  513. public override Value ToValue(short obj, object parent)
  514. => Value.From(obj);
  515. }
  516. internal class UShortConverter : ValueConverter<ushort>
  517. {
  518. public override ushort FromValue(Value value, object parent)
  519. => (ushort)Converter<long>.Default.FromValue(value, parent);
  520. public override Value ToValue(ushort obj, object parent)
  521. => Value.From(obj);
  522. }
  523. internal class ByteConverter : ValueConverter<byte>
  524. {
  525. public override byte FromValue(Value value, object parent)
  526. => (byte)Converter<long>.Default.FromValue(value, parent);
  527. public override Value ToValue(byte obj, object parent)
  528. => Value.From(obj);
  529. }
  530. internal class SByteConverter : ValueConverter<sbyte>
  531. {
  532. public override sbyte FromValue(Value value, object parent)
  533. => (sbyte)Converter<long>.Default.FromValue(value, parent);
  534. public override Value ToValue(sbyte obj, object parent)
  535. => Value.From(obj);
  536. }
  537. internal class DecimalConverter : ValueConverter<decimal>
  538. {
  539. public override decimal FromValue(Value value, object parent)
  540. => Converter.FloatValue(value) ?? throw new ArgumentException("Value not a numeric value", nameof(value));
  541. public override Value ToValue(decimal obj, object parent)
  542. => Value.From(obj);
  543. }
  544. internal class FloatConverter : ValueConverter<float>
  545. {
  546. public override float FromValue(Value value, object parent)
  547. => (float)Converter<decimal>.Default.FromValue(value, parent);
  548. public override Value ToValue(float obj, object parent)
  549. => Value.From((decimal)obj);
  550. }
  551. internal class DoubleConverter : ValueConverter<double>
  552. {
  553. public override double FromValue(Value value, object parent)
  554. => (double)Converter<decimal>.Default.FromValue(value, parent);
  555. public override Value ToValue(double obj, object parent)
  556. => Value.From((decimal)obj);
  557. }
  558. internal class BooleanConverter : ValueConverter<bool>
  559. {
  560. public override bool FromValue(Value value, object parent)
  561. => (value as Boolean)?.Value ?? throw new ArgumentException("Value not a Boolean", nameof(value));
  562. public override Value ToValue(bool obj, object parent)
  563. => Value.From(obj);
  564. }
  565. }