using System; using System.Collections.Generic; using System.Globalization; namespace BepInEx.Configuration { /// /// Serializer/deserializer used by the config system. /// public static class TomlTypeConverter { private static Dictionary TypeConverters { get; } = new Dictionary { [typeof(string)] = new TypeConverter { ConvertToString = (obj, type) => (string)obj, ConvertToObject = (str, type) => str, }, [typeof(bool)] = new TypeConverter { ConvertToString = (obj, type) => obj.ToString().ToLowerInvariant(), ConvertToObject = (str, type) => bool.Parse(str), }, [typeof(byte)] = new TypeConverter { ConvertToString = (obj, type) => obj.ToString(), ConvertToObject = (str, type) => byte.Parse(str), }, //integral types [typeof(sbyte)] = new TypeConverter { ConvertToString = (obj, type) => obj.ToString(), ConvertToObject = (str, type) => sbyte.Parse(str), }, [typeof(byte)] = new TypeConverter { ConvertToString = (obj, type) => obj.ToString(), ConvertToObject = (str, type) => byte.Parse(str), }, [typeof(short)] = new TypeConverter { ConvertToString = (obj, type) => obj.ToString(), ConvertToObject = (str, type) => short.Parse(str), }, [typeof(ushort)] = new TypeConverter { ConvertToString = (obj, type) => obj.ToString(), ConvertToObject = (str, type) => ushort.Parse(str), }, [typeof(int)] = new TypeConverter { ConvertToString = (obj, type) => obj.ToString(), ConvertToObject = (str, type) => int.Parse(str), }, [typeof(uint)] = new TypeConverter { ConvertToString = (obj, type) => obj.ToString(), ConvertToObject = (str, type) => uint.Parse(str), }, [typeof(long)] = new TypeConverter { ConvertToString = (obj, type) => obj.ToString(), ConvertToObject = (str, type) => long.Parse(str), }, [typeof(ulong)] = new TypeConverter { ConvertToString = (obj, type) => obj.ToString(), ConvertToObject = (str, type) => ulong.Parse(str), }, //floating point types [typeof(float)] = new TypeConverter { ConvertToString = (obj, type) => ((float)obj).ToString(NumberFormatInfo.InvariantInfo), ConvertToObject = (str, type) => float.Parse(str, NumberFormatInfo.InvariantInfo), }, [typeof(double)] = new TypeConverter { ConvertToString = (obj, type) => ((double)obj).ToString(NumberFormatInfo.InvariantInfo), ConvertToObject = (str, type) => double.Parse(str, NumberFormatInfo.InvariantInfo), }, [typeof(decimal)] = new TypeConverter { ConvertToString = (obj, type) => ((decimal)obj).ToString(NumberFormatInfo.InvariantInfo), ConvertToObject = (str, type) => decimal.Parse(str, NumberFormatInfo.InvariantInfo), }, //enums are special [typeof(Enum)] = new TypeConverter { ConvertToString = (obj, type) => obj.ToString(), ConvertToObject = (str, type) => Enum.Parse(type, str, true), }, }; public static string ConvertToString(object value, Type valueType) { var conv = GetConverter(valueType); if (conv == null) throw new InvalidOperationException($"Cannot convert from type {valueType}"); return conv.ConvertToString(value, valueType); } public static T ConvertToValue(string value) { return (T)ConvertToValue(value, typeof(T)); } public static object ConvertToValue(string value, Type valueType) { var conv = GetConverter(valueType); if (conv == null) throw new InvalidOperationException($"Cannot convert to type {valueType.Name}"); return conv.ConvertToObject(value, valueType); } public static TypeConverter GetConverter(Type valueType) { if (valueType == null) throw new ArgumentNullException(nameof(valueType)); if (valueType.IsEnum) return TypeConverters[typeof(Enum)]; TypeConverters.TryGetValue(valueType, out var result); return result; } public static void AddConverter(Type type, TypeConverter converter) { if (type == null) throw new ArgumentNullException(nameof(type)); if (converter == null) throw new ArgumentNullException(nameof(converter)); if (CanConvert(type)) throw new ArgumentException("The specified type already has a converter assigned to it", nameof(type)); TypeConverters.Add(type, converter); } public static bool CanConvert(Type type) { return GetConverter(type) != null; } public static IEnumerable GetSupportedTypes() { return TypeConverters.Keys; } } }