From 4a0675399059fe685164b2fa19e9749372b1595a Mon Sep 17 00:00:00 2001 From: RogueException Date: Tue, 26 Jul 2016 19:01:51 -0300 Subject: [PATCH] Cleaned up TypeReaders --- src/Discord.Net.Commands/CommandService.cs | 123 ++++++------------ src/Discord.Net.Commands/PrimitiveParsers.cs | 33 +++++ .../Readers/EnumTypeReader.cs | 22 +--- .../Readers/GenericTypeReader.cs | 17 --- .../Readers/SimpleTypeReader.cs | 23 ++++ 5 files changed, 100 insertions(+), 118 deletions(-) create mode 100644 src/Discord.Net.Commands/PrimitiveParsers.cs delete mode 100644 src/Discord.Net.Commands/Readers/GenericTypeReader.cs create mode 100644 src/Discord.Net.Commands/Readers/SimpleTypeReader.cs diff --git a/src/Discord.Net.Commands/CommandService.cs b/src/Discord.Net.Commands/CommandService.cs index 46c5aaa39..cd09c47b6 100644 --- a/src/Discord.Net.Commands/CommandService.cs +++ b/src/Discord.Net.Commands/CommandService.cs @@ -2,7 +2,6 @@ using System.Collections.Concurrent; using System.Collections.Generic; using System.Collections.Immutable; -using System.Globalization; using System.Linq; using System.Reflection; using System.Threading; @@ -27,94 +26,56 @@ namespace Discord.Commands _map = new CommandMap(); _typeReaders = new ConcurrentDictionary { - [typeof(string)] = new GenericTypeReader((m, s) => Task.FromResult(TypeReaderResult.FromSuccess(s))), - [typeof(byte)] = new GenericTypeReader((m, s) => - { - byte value; - if (byte.TryParse(s, out value)) return Task.FromResult(TypeReaderResult.FromSuccess(value)); - return Task.FromResult(TypeReaderResult.FromError(CommandError.ParseFailed, "Failed to parse Byte")); - }), - [typeof(sbyte)] = new GenericTypeReader((m, s) => - { - sbyte value; - if (sbyte.TryParse(s, out value)) return Task.FromResult(TypeReaderResult.FromSuccess(value)); - return Task.FromResult(TypeReaderResult.FromError(CommandError.ParseFailed, "Failed to parse SByte")); - }), - [typeof(ushort)] = new GenericTypeReader((m, s) => - { - ushort value; - if (ushort.TryParse(s, out value)) return Task.FromResult(TypeReaderResult.FromSuccess(value)); - return Task.FromResult(TypeReaderResult.FromError(CommandError.ParseFailed, "Failed to parse UInt16")); - }), - [typeof(short)] = new GenericTypeReader((m, s) => - { - short value; - if (short.TryParse(s, out value)) return Task.FromResult(TypeReaderResult.FromSuccess(value)); - return Task.FromResult(TypeReaderResult.FromError(CommandError.ParseFailed, "Failed to parse Int16")); - }), - [typeof(uint)] = new GenericTypeReader((m, s) => - { - uint value; - if (uint.TryParse(s, out value)) return Task.FromResult(TypeReaderResult.FromSuccess(value)); - return Task.FromResult(TypeReaderResult.FromError(CommandError.ParseFailed, "Failed to parse UInt32")); - }), - [typeof(int)] = new GenericTypeReader((m, s) => - { - int value; - if (int.TryParse(s, out value)) return Task.FromResult(TypeReaderResult.FromSuccess(value)); - return Task.FromResult(TypeReaderResult.FromError(CommandError.ParseFailed, "Failed to parse Int32")); - }), - [typeof(ulong)] = new GenericTypeReader((m, s) => - { - ulong value; - if (ulong.TryParse(s, out value)) return Task.FromResult(TypeReaderResult.FromSuccess(value)); - return Task.FromResult(TypeReaderResult.FromError(CommandError.ParseFailed, "Failed to parse UInt64")); - }), - [typeof(long)] = new GenericTypeReader((m, s) => - { - long value; - if (long.TryParse(s, out value)) return Task.FromResult(TypeReaderResult.FromSuccess(value)); - return Task.FromResult(TypeReaderResult.FromError(CommandError.ParseFailed, "Failed to parse Int64")); - }), - [typeof(float)] = new GenericTypeReader((m, s) => - { - float value; - if (float.TryParse(s, out value)) return Task.FromResult(TypeReaderResult.FromSuccess(value)); - return Task.FromResult(TypeReaderResult.FromError(CommandError.ParseFailed, "Failed to parse Single")); - }), - [typeof(double)] = new GenericTypeReader((m, s) => - { - double value; - if (double.TryParse(s, out value)) return Task.FromResult(TypeReaderResult.FromSuccess(value)); - return Task.FromResult(TypeReaderResult.FromError(CommandError.ParseFailed, "Failed to parse Double")); - }), - [typeof(decimal)] = new GenericTypeReader((m, s) => - { - decimal value; - if (decimal.TryParse(s, out value)) return Task.FromResult(TypeReaderResult.FromSuccess(value)); - return Task.FromResult(TypeReaderResult.FromError(CommandError.ParseFailed, "Failed to parse Decimal")); - }), - [typeof(DateTime)] = new GenericTypeReader((m, s) => - { - DateTime value; - if (DateTime.TryParse(s, out value)) return Task.FromResult(TypeReaderResult.FromSuccess(value)); - return Task.FromResult(TypeReaderResult.FromError(CommandError.ParseFailed, "Failed to parse DateTime")); - }), - [typeof(DateTimeOffset)] = new GenericTypeReader((m, s) => - { - DateTimeOffset value; - if (DateTimeOffset.TryParse(s, out value)) return Task.FromResult(TypeReaderResult.FromSuccess(value)); - return Task.FromResult(TypeReaderResult.FromError(CommandError.ParseFailed, "Failed to parse DateTimeOffset")); - }), + [typeof(string)] = new SimpleTypeReader(), + [typeof(byte)] = new SimpleTypeReader(), + [typeof(sbyte)] = new SimpleTypeReader(), + [typeof(ushort)] = new SimpleTypeReader(), + [typeof(short)] = new SimpleTypeReader(), + [typeof(uint)] = new SimpleTypeReader(), + [typeof(int)] = new SimpleTypeReader(), + [typeof(ulong)] = new SimpleTypeReader(), + [typeof(long)] = new SimpleTypeReader(), + [typeof(float)] = new SimpleTypeReader(), + [typeof(double)] = new SimpleTypeReader(), + [typeof(decimal)] = new SimpleTypeReader(), + [typeof(DateTime)] = new SimpleTypeReader(), + [typeof(DateTimeOffset)] = new SimpleTypeReader(), + + //TODO: Do we want to support any other interfaces? + + //[typeof(IMentionable)] = new GeneralTypeReader(), + //[typeof(ISnowflakeEntity)] = new GeneralTypeReader(), + //[typeof(IEntity)] = new GeneralTypeReader(), [typeof(IMessage)] = new MessageTypeReader(), + //[typeof(IAttachment)] = new xxx(), + //[typeof(IEmbed)] = new xxx(), + [typeof(IChannel)] = new ChannelTypeReader(), + [typeof(IDMChannel)] = new ChannelTypeReader(), + [typeof(IGroupChannel)] = new ChannelTypeReader(), [typeof(IGuildChannel)] = new ChannelTypeReader(), + [typeof(IMessageChannel)] = new ChannelTypeReader(), + [typeof(IPrivateChannel)] = new ChannelTypeReader(), [typeof(ITextChannel)] = new ChannelTypeReader(), [typeof(IVoiceChannel)] = new ChannelTypeReader(), + + //[typeof(IGuild)] = new GuildTypeReader(), + //[typeof(IUserGuild)] = new GuildTypeReader(), + //[typeof(IGuildIntegration)] = new xxx(), + [typeof(IRole)] = new RoleTypeReader(), + + //[typeof(IInvite)] = new InviteTypeReader(), + //[typeof(IInviteMetadata)] = new InviteTypeReader(), + [typeof(IUser)] = new UserTypeReader(), - [typeof(IGuildUser)] = new UserTypeReader() + [typeof(IGroupUser)] = new UserTypeReader(), + [typeof(IGuildUser)] = new UserTypeReader(), + //[typeof(ISelfUser)] = new UserTypeReader(), + //[typeof(IPresence)] = new UserTypeReader(), + //[typeof(IVoiceState)] = new UserTypeReader(), + //[typeof(IConnection)] = new xxx(), }; } diff --git a/src/Discord.Net.Commands/PrimitiveParsers.cs b/src/Discord.Net.Commands/PrimitiveParsers.cs new file mode 100644 index 000000000..0e60078af --- /dev/null +++ b/src/Discord.Net.Commands/PrimitiveParsers.cs @@ -0,0 +1,33 @@ +using System; +using System.Collections.Generic; +using System.Collections.Immutable; + +namespace Discord.Commands +{ + internal delegate bool TryParseDelegate(string str, out T value); + + internal static class PrimitiveParsers + { + private static readonly IReadOnlyDictionary _parsers; + + static PrimitiveParsers() + { + var parserBuilder = ImmutableDictionary.CreateBuilder(); + parserBuilder[typeof(string)] = (TryParseDelegate)delegate(string str, out string value) { value = str; return true; }; + parserBuilder[typeof(sbyte)] = (TryParseDelegate)sbyte.TryParse; + parserBuilder[typeof(byte)] = (TryParseDelegate)byte.TryParse; + parserBuilder[typeof(short)] = (TryParseDelegate)short.TryParse; + parserBuilder[typeof(ushort)] = (TryParseDelegate)ushort.TryParse; + parserBuilder[typeof(int)] = (TryParseDelegate)int.TryParse; + parserBuilder[typeof(uint)] = (TryParseDelegate)uint.TryParse; + parserBuilder[typeof(long)] = (TryParseDelegate)long.TryParse; + parserBuilder[typeof(ulong)] = (TryParseDelegate)ulong.TryParse; + parserBuilder[typeof(DateTime)] = (TryParseDelegate)DateTime.TryParse; + parserBuilder[typeof(DateTimeOffset)] = (TryParseDelegate)DateTimeOffset.TryParse; + _parsers = parserBuilder.ToImmutable(); + } + + public static TryParseDelegate Get() => (TryParseDelegate)_parsers[typeof(T)]; + public static Delegate Get(Type type) => _parsers[type]; + } +} diff --git a/src/Discord.Net.Commands/Readers/EnumTypeReader.cs b/src/Discord.Net.Commands/Readers/EnumTypeReader.cs index ca2b2159c..8e5313118 100644 --- a/src/Discord.Net.Commands/Readers/EnumTypeReader.cs +++ b/src/Discord.Net.Commands/Readers/EnumTypeReader.cs @@ -7,31 +7,13 @@ using System.Threading.Tasks; namespace Discord.Commands { - delegate bool TryParseDelegate(string str, out T value); - internal static class EnumTypeReader - { - private static readonly IReadOnlyDictionary _parsers; - - static EnumTypeReader() - { - var parserBuilder = ImmutableDictionary.CreateBuilder(); - parserBuilder[typeof(sbyte)] = (TryParseDelegate)sbyte.TryParse; - parserBuilder[typeof(byte)] = (TryParseDelegate)byte.TryParse; - parserBuilder[typeof(short)] = (TryParseDelegate)short.TryParse; - parserBuilder[typeof(ushort)] = (TryParseDelegate)ushort.TryParse; - parserBuilder[typeof(int)] = (TryParseDelegate)int.TryParse; - parserBuilder[typeof(uint)] = (TryParseDelegate)uint.TryParse; - parserBuilder[typeof(long)] = (TryParseDelegate)long.TryParse; - parserBuilder[typeof(ulong)] = (TryParseDelegate)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] }); + return (TypeReader)constructor.Invoke(new object[] { type, PrimitiveParsers.Get(baseType) }); } } diff --git a/src/Discord.Net.Commands/Readers/GenericTypeReader.cs b/src/Discord.Net.Commands/Readers/GenericTypeReader.cs deleted file mode 100644 index 97bc7d94c..000000000 --- a/src/Discord.Net.Commands/Readers/GenericTypeReader.cs +++ /dev/null @@ -1,17 +0,0 @@ -using System; -using System.Threading.Tasks; - -namespace Discord.Commands -{ - internal class GenericTypeReader : TypeReader - { - private readonly Func> _action; - - public GenericTypeReader(Func> action) - { - _action = action; - } - - public override Task Read(IMessage context, string input) => _action(context, input); - } -} diff --git a/src/Discord.Net.Commands/Readers/SimpleTypeReader.cs b/src/Discord.Net.Commands/Readers/SimpleTypeReader.cs new file mode 100644 index 000000000..a3822084b --- /dev/null +++ b/src/Discord.Net.Commands/Readers/SimpleTypeReader.cs @@ -0,0 +1,23 @@ +using System.Threading.Tasks; + +namespace Discord.Commands +{ + internal class SimpleTypeReader : TypeReader + { + private readonly TryParseDelegate _tryParse; + + public SimpleTypeReader() + { + _tryParse = PrimitiveParsers.Get(); + } + + public override Task Read(IMessage context, string input) + { + T value; + if (_tryParse(input, out value)) + return Task.FromResult(TypeReaderResult.FromSuccess(value)); + else + return Task.FromResult(TypeReaderResult.FromError(CommandError.ParseFailed, $"Failed to parse {typeof(T).Name}")); + } + } +}