// Copyright (c) 2022 bradson // This Source Code Form is subject to the terms of the Mozilla Public // License, v. 2.0. If a copy of the MPL was not distributed with this // file, You can obtain one at https://mozilla.org/MPL/2.0/. namespace FisheryLib.FunctionPointers; public static class Convert where TFrom : IConvertible { public static class To { public static readonly unsafe delegate* Default = Convert.GetDefaultConverter(); } /// /// Used when TFrom isn't a known sealed type, i.e. with just the IConvertible interface /// internal static class Fallback { internal static readonly Func Func = Convert.GetDefaultConverterFunc(); internal static TTo FallbackMethod(TFrom from, IFormatProvider provider) => Func(from, provider); } } internal static class Convert { private static MethodInfo GetConverterMethod(Type to) where TFrom : IConvertible { var info = typeof(TFrom).GetMethod(GetConvertMethodName(to)); if (info.GetParameters().Length > 1) { info = typeof(Convert) .GetMethod(nameof(ConvertToType), AccessTools.allDeclared) .MakeGenericMethod(new[] { typeof(TFrom), to }); } return info; } internal static Func GetDefaultConverterFunc() where TFrom : IConvertible => (Func)GetConverterMethod(typeof(TTo)) .CreateDelegate(typeof(Func)); internal static unsafe delegate* GetDefaultConverter() where TFrom : IConvertible => !typeof(TFrom).IsValueType && (!typeof(TFrom).IsSealed || typeof(TFrom).IsInterface || typeof(TFrom).IsAbstract) ? &Convert.Fallback.FallbackMethod : (delegate*)GetConverterMethod(typeof(TTo)) .MethodHandle.GetFunctionPointer(); private static TTo ConvertToType(TFrom from, IFormatProvider provider) where TFrom : IConvertible => (TTo)from.ToType(typeof(TTo), provider); private static string GetConvertMethodName(Type type) => type == typeof(bool) ? nameof(IConvertible.ToBoolean) : type == typeof(char) ? nameof(IConvertible.ToChar) : type == typeof(sbyte) ? nameof(IConvertible.ToSByte) : type == typeof(byte) ? nameof(IConvertible.ToByte) : type == typeof(short) ? nameof(IConvertible.ToInt16) : type == typeof(ushort) ? nameof(IConvertible.ToUInt16) : type == typeof(int) ? nameof(IConvertible.ToInt32) : type == typeof(uint) ? nameof(IConvertible.ToUInt32) : type == typeof(long) ? nameof(IConvertible.ToInt64) : type == typeof(ulong) ? nameof(IConvertible.ToUInt64) : type == typeof(float) ? nameof(IConvertible.ToSingle) : type == typeof(double) ? nameof(IConvertible.ToDouble) : type == typeof(decimal) ? nameof(IConvertible.ToDecimal) : type == typeof(DateTime) ? nameof(IConvertible.ToDateTime) : type == typeof(string) ? nameof(IConvertible.ToString) //: type == typeof(object) //? value : nameof(IConvertible.ToType); }