|
@@ -1,54 +1,84 @@ |
|
|
using System; |
|
|
using System; |
|
|
using System.Collections.Generic; |
|
|
using System.Collections.Generic; |
|
|
|
|
|
using System.Collections.Immutable; |
|
|
using System.Linq; |
|
|
using System.Linq; |
|
|
|
|
|
using System.Reflection; |
|
|
using System.Threading.Tasks; |
|
|
using System.Threading.Tasks; |
|
|
|
|
|
|
|
|
namespace Discord.Commands |
|
|
namespace Discord.Commands |
|
|
{ |
|
|
{ |
|
|
internal class EnumTypeReader : TypeReader |
|
|
|
|
|
|
|
|
delegate bool TryParseDelegate<T>(string str, out T value); |
|
|
|
|
|
|
|
|
|
|
|
internal static class EnumTypeReader |
|
|
|
|
|
{ |
|
|
|
|
|
private static readonly IReadOnlyDictionary<Type, object> _parsers; |
|
|
|
|
|
|
|
|
|
|
|
static EnumTypeReader() |
|
|
|
|
|
{ |
|
|
|
|
|
var parserBuilder = ImmutableDictionary.CreateBuilder<Type, object>(); |
|
|
|
|
|
parserBuilder[typeof(sbyte)] = (TryParseDelegate<sbyte>)sbyte.TryParse; |
|
|
|
|
|
parserBuilder[typeof(byte)] = (TryParseDelegate<byte>)byte.TryParse; |
|
|
|
|
|
parserBuilder[typeof(short)] = (TryParseDelegate<short>)short.TryParse; |
|
|
|
|
|
parserBuilder[typeof(ushort)] = (TryParseDelegate<ushort>)ushort.TryParse; |
|
|
|
|
|
parserBuilder[typeof(int)] = (TryParseDelegate<int>)int.TryParse; |
|
|
|
|
|
parserBuilder[typeof(uint)] = (TryParseDelegate<uint>)uint.TryParse; |
|
|
|
|
|
parserBuilder[typeof(long)] = (TryParseDelegate<long>)long.TryParse; |
|
|
|
|
|
parserBuilder[typeof(ulong)] = (TryParseDelegate<ulong>)ulong.TryParse; |
|
|
|
|
|
_parsers = parserBuilder.ToImmutable(); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
public static TypeReader GetReader(Type type) |
|
|
|
|
|
{ |
|
|
|
|
|
Type baseType = Enum.GetUnderlyingType(type); |
|
|
|
|
|
var constructor = typeof(EnumTypeReader<>).MakeGenericType(baseType).GetTypeInfo().DeclaredConstructors.First(); |
|
|
|
|
|
return (TypeReader)constructor.Invoke(new object[] { type, _parsers[baseType] }); |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
internal class EnumTypeReader<T> : TypeReader |
|
|
{ |
|
|
{ |
|
|
private readonly Dictionary<string, object> stringValues; |
|
|
|
|
|
private readonly Dictionary<int, object> intValues; |
|
|
|
|
|
private readonly Type enumType; |
|
|
|
|
|
|
|
|
private readonly IReadOnlyDictionary<string, object> _enumsByName; |
|
|
|
|
|
private readonly IReadOnlyDictionary<T, object> _enumsByValue; |
|
|
|
|
|
private readonly Type _enumType; |
|
|
|
|
|
private readonly TryParseDelegate<T> _tryParse; |
|
|
|
|
|
|
|
|
|
|
|
public EnumTypeReader(Type type, TryParseDelegate<T> parser) |
|
|
|
|
|
{ |
|
|
|
|
|
_enumType = type; |
|
|
|
|
|
_tryParse = parser; |
|
|
|
|
|
|
|
|
|
|
|
var byNameBuilder = ImmutableDictionary.CreateBuilder<string, object>(); |
|
|
|
|
|
var byValueBuilder = ImmutableDictionary.CreateBuilder<T, object>(); |
|
|
|
|
|
|
|
|
|
|
|
foreach (var v in Enum.GetValues(_enumType)) |
|
|
|
|
|
{ |
|
|
|
|
|
byNameBuilder.Add(v.ToString().ToLower(), v); |
|
|
|
|
|
byValueBuilder.Add((T)v, v); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
_enumsByName = byNameBuilder.ToImmutable(); |
|
|
|
|
|
_enumsByValue = byValueBuilder.ToImmutable(); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
public override Task<TypeReaderResult> Read(IMessage context, string input) |
|
|
public override Task<TypeReaderResult> Read(IMessage context, string input) |
|
|
{ |
|
|
{ |
|
|
int inputAsInt; |
|
|
|
|
|
|
|
|
T intValue; |
|
|
object enumValue; |
|
|
object enumValue; |
|
|
|
|
|
|
|
|
if (int.TryParse(input, out inputAsInt)) |
|
|
|
|
|
|
|
|
if (_tryParse(input, out intValue)) |
|
|
{ |
|
|
{ |
|
|
if (intValues.TryGetValue(inputAsInt, out enumValue)) |
|
|
|
|
|
|
|
|
if (_enumsByValue.TryGetValue(intValue, out enumValue)) |
|
|
return Task.FromResult(TypeReaderResult.FromSuccess(enumValue)); |
|
|
return Task.FromResult(TypeReaderResult.FromSuccess(enumValue)); |
|
|
else |
|
|
else |
|
|
return Task.FromResult(TypeReaderResult.FromError(CommandError.CastFailed, $"Value is not a {enumType.Name}")); |
|
|
|
|
|
|
|
|
return Task.FromResult(TypeReaderResult.FromError(CommandError.CastFailed, $"Value is not a {_enumType.Name}")); |
|
|
} |
|
|
} |
|
|
else |
|
|
else |
|
|
{ |
|
|
{ |
|
|
if (stringValues.TryGetValue(input.ToLower(), out enumValue)) |
|
|
|
|
|
|
|
|
if (_enumsByName.TryGetValue(input.ToLower(), out enumValue)) |
|
|
return Task.FromResult(TypeReaderResult.FromSuccess(enumValue)); |
|
|
return Task.FromResult(TypeReaderResult.FromSuccess(enumValue)); |
|
|
else |
|
|
else |
|
|
return Task.FromResult(TypeReaderResult.FromError(CommandError.CastFailed, $"Value is not a {enumType.Name}")); |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
public EnumTypeReader(Type type) |
|
|
|
|
|
{ |
|
|
|
|
|
enumType = type; |
|
|
|
|
|
|
|
|
|
|
|
var stringValuesBuilder = new Dictionary<string, object>(); |
|
|
|
|
|
var intValuesBuilder = new Dictionary<int, object>(); |
|
|
|
|
|
|
|
|
|
|
|
var values = Enum.GetValues(enumType); |
|
|
|
|
|
|
|
|
|
|
|
foreach (var v in values) |
|
|
|
|
|
{ |
|
|
|
|
|
stringValuesBuilder.Add(v.ToString().ToLower(), v); |
|
|
|
|
|
intValuesBuilder.Add((int)v, v); |
|
|
|
|
|
|
|
|
return Task.FromResult(TypeReaderResult.FromError(CommandError.CastFailed, $"Value is not a {_enumType.Name}")); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
stringValues = stringValuesBuilder; |
|
|
|
|
|
intValues = intValuesBuilder; |
|
|
|
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
} |