using IPA.Config.Data;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace IPA.Config.Stores.Converters
{
///
/// Provides utility functions for custom converters.
///
public static class Converter
{
///
/// Gets the integral value of a , coercing a if necessary,
/// or if is not an or .
///
/// the to get the integral value of
/// the integral value of , or
public static long? IntValue(Value val)
=> val is Integer inte ? inte.Value :
val is FloatingPoint fp ? fp.AsInteger()?.Value :
null;
///
/// Gets the floaing point value of a , coercing an if necessary,
/// or if is not an or .
///
/// the to get the floaing point value of
/// the floaing point value of , or
public static decimal? FloatValue(Value val)
=> val is FloatingPoint fp ? fp.Value :
val is Integer inte ? inte.AsFloat()?.Value :
null;
internal interface IValConv
{
ValueConverter Get();
}
internal class ValConv : IValConv where T : struct
{
private static readonly IValConv Impl = ValConvImpls.Impl as IValConv ?? new ValConv();
public ValueConverter Get() => Impl.Get();
ValueConverter IValConv.Get()
=> null; // default to null
}
private class ValConvImpls : IValConv,
IValConv, IValConv,
IValConv, IValConv,
IValConv, IValConv,
IValConv, IValConv,
IValConv, IValConv,
IValConv, IValConv,
IValConv
{
internal static readonly ValConvImpls Impl = new ValConvImpls();
ValueConverter IValConv.Get()
=> new CharConverter();
ValueConverter IValConv.Get()
=> new LongConverter();
ValueConverter IValConv.Get()
=> new ULongConverter();
ValueConverter IValConv.Get()
=> new IntPtrConverter();
ValueConverter IValConv.Get()
=> new UIntPtrConverter();
ValueConverter IValConv.Get()
=> new IntConverter();
ValueConverter IValConv.Get()
=> new UIntConverter();
ValueConverter IValConv.Get()
=> new ShortConverter();
ValueConverter IValConv.Get()
=> new UShortConverter();
ValueConverter IValConv.Get()
=> new ByteConverter();
ValueConverter IValConv.Get()
=> new SByteConverter();
ValueConverter IValConv.Get()
=> new FloatConverter();
ValueConverter IValConv.Get()
=> new DoubleConverter();
ValueConverter IValConv.Get()
=> new DecimalConverter();
}
}
///
/// Provides generic utilities for converters for certain types.
///
/// the type of the that this works on
public static class Converter
{
private static ValueConverter defaultConverter = null;
///
/// Gets the default for the current type.
///
public static ValueConverter Default
{
get
{
if (defaultConverter == null)
defaultConverter = MakeDefault();
return defaultConverter;
}
}
private static ValueConverter MakeDefault()
{
var t = typeof(T);
if (t.IsValueType)
{ // we have to do this garbo to make it accept the thing that we know is a value type at instantiation time
if (t.IsGenericType && t.GetGenericTypeDefinition() == typeof(Nullable<>))
{ // this is a Nullable
return Activator.CreateInstance(typeof(NullableConverter<>).MakeGenericType(Nullable.GetUnderlyingType(t))) as ValueConverter;
}
var valConv = Activator.CreateInstance(typeof(Converter.ValConv<>).MakeGenericType(t)) as Converter.IValConv;
return valConv.Get();
}
else if (t == typeof(string))
{
return new StringConverter() as ValueConverter;
}
else
{
return Activator.CreateInstance(typeof(CustomObjectConverter<>).MakeGenericType(t)) as ValueConverter;
}
}
}
///
/// A converter for a .
///
/// the underlying type of the
public class NullableConverter : ValueConverter where T : struct
{
private readonly ValueConverter baseConverter;
///
/// Creates a converter with the default converter for the base type.
/// Equivalent to
///
/// new NullableConverter(Converter<T>.Default)
///
///
///
///
public NullableConverter() : this(Converter.Default) { }
///
/// Creates a converter with the given underlying .
///
/// the undlerlying to use
public NullableConverter(ValueConverter underlying)
=> baseConverter = underlying;
///
/// Converts a tree to a value.
///
/// the tree to convert
/// the object which will own the created object
/// the object represented by
public override T? FromValue(Value value, object parent)
=> value == null ? null : new T?(baseConverter.FromValue(value, parent));
///
/// Converts a nullable to a tree.
///
/// the value to serialize
/// the object which owns
/// a tree representing .
public override Value ToValue(T? obj, object parent)
=> obj == null ? null : baseConverter.ToValue(obj.Value, parent);
}
internal class StringConverter : ValueConverter
{
public override string FromValue(Value value, object parent)
=> (value as Text)?.Value;
public override Value ToValue(string obj, object parent)
=> Value.From(obj);
}
internal class CharConverter : ValueConverter
{
public override char FromValue(Value value, object parent)
=> (value as Text).Value[0]; // can throw nullptr
public override Value ToValue(char obj, object parent)
=> Value.From(char.ToString(obj));
}
internal class LongConverter : ValueConverter
{
public override long FromValue(Value value, object parent)
=> Converter.IntValue(value) ?? throw new ArgumentException("Value not a numeric value", nameof(value));
public override Value ToValue(long obj, object parent)
=> Value.From(obj);
}
internal class ULongConverter : ValueConverter
{
public override ulong FromValue(Value value, object parent)
=> (ulong)(Converter.FloatValue(value) ?? throw new ArgumentException("Value not a numeric value", nameof(value)));
public override Value ToValue(ulong obj, object parent)
=> Value.From(obj);
}
internal class IntPtrConverter : ValueConverter
{
public override IntPtr FromValue(Value value, object parent)
=> (IntPtr)Converter.Default.FromValue(value, parent);
public override Value ToValue(IntPtr obj, object parent)
=> Value.From((long)obj);
}
internal class UIntPtrConverter : ValueConverter
{
public override UIntPtr FromValue(Value value, object parent)
=> (UIntPtr)Converter.Default.FromValue(value, parent);
public override Value ToValue(UIntPtr obj, object parent)
=> Value.From((decimal)obj);
}
internal class IntConverter : ValueConverter
{
public override int FromValue(Value value, object parent)
=> (int)Converter.Default.FromValue(value, parent);
public override Value ToValue(int obj, object parent)
=> Value.From(obj);
}
internal class UIntConverter : ValueConverter
{
public override uint FromValue(Value value, object parent)
=> (uint)Converter.Default.FromValue(value, parent);
public override Value ToValue(uint obj, object parent)
=> Value.From(obj);
}
internal class ShortConverter : ValueConverter
{
public override short FromValue(Value value, object parent)
=> (short)Converter.Default.FromValue(value, parent);
public override Value ToValue(short obj, object parent)
=> Value.From(obj);
}
internal class UShortConverter : ValueConverter
{
public override ushort FromValue(Value value, object parent)
=> (ushort)Converter.Default.FromValue(value, parent);
public override Value ToValue(ushort obj, object parent)
=> Value.From(obj);
}
internal class ByteConverter : ValueConverter
{
public override byte FromValue(Value value, object parent)
=> (byte)Converter.Default.FromValue(value, parent);
public override Value ToValue(byte obj, object parent)
=> Value.From(obj);
}
internal class SByteConverter : ValueConverter
{
public override sbyte FromValue(Value value, object parent)
=> (sbyte)Converter.Default.FromValue(value, parent);
public override Value ToValue(sbyte obj, object parent)
=> Value.From(obj);
}
internal class DecimalConverter : ValueConverter
{
public override decimal FromValue(Value value, object parent)
=> Converter.FloatValue(value) ?? throw new ArgumentException("Value not a numeric value", nameof(value));
public override Value ToValue(decimal obj, object parent)
=> Value.From(obj);
}
internal class FloatConverter : ValueConverter
{
public override float FromValue(Value value, object parent)
=> (float)Converter.Default.FromValue(value, parent);
public override Value ToValue(float obj, object parent)
=> Value.From((decimal)obj);
}
internal class DoubleConverter : ValueConverter
{
public override double FromValue(Value value, object parent)
=> (double)Converter.Default.FromValue(value, parent);
public override Value ToValue(double obj, object parent)
=> Value.From((decimal)obj);
}
}