diff --git a/src/prefix_argument/argument_trait.rs b/src/prefix_argument/argument_trait.rs index 336d324099b..8a6bf6fee7a 100644 --- a/src/prefix_argument/argument_trait.rs +++ b/src/prefix_argument/argument_trait.rs @@ -2,10 +2,7 @@ //! the auto-deref specialization emulation code to e.g. support more strings for bool parameters //! instead of the `FromStr` ones -use super::{ - pop_string, InvalidBool, InvalidChannelId, InvalidRoleId, InvalidUserId, MissingAttachment, - TooFewArguments, -}; +use super::{pop_string, InvalidBool, MissingAttachment, TooFewArguments}; use crate::serenity_prelude as serenity; use std::marker::PhantomData; @@ -139,83 +136,56 @@ impl<'a> PopArgumentHack<'a, serenity::Attachment> for &PhantomData PopArgumentHack<'a, serenity::UserId> for &PhantomData { - async fn pop_from( - self, - args: &'a str, - attachment_index: usize, - ctx: &serenity::Context, - msg: &serenity::Message, - ) -> Result< - (&'a str, usize, serenity::UserId), - (Box, Option), - > { - let (args, string) = - pop_string(args).map_err(|_| (TooFewArguments::default().into(), None))?; - - if let Some(user_id) = string - .parse() - .ok() - .or_else(|| serenity::utils::parse_user_mention(&string)) - { - Ok((args.trim_start(), attachment_index, user_id)) - } else { - Err((InvalidUserId::default().into(), Some(string))) +/// Macro to allow for using mentions in snowflake types +macro_rules! snowflake_pop_argument { + ($type:ty, $parse_fn:ident, $error_type:ident) => { + /// Error thrown when the user enters a string that cannot be parsed correctly. + #[derive(Default, Debug)] + pub struct $error_type { + #[doc(hidden)] + pub __non_exhaustive: (), } - } -} -#[async_trait::async_trait] -impl<'a> PopArgumentHack<'a, serenity::RoleId> for &PhantomData { - async fn pop_from( - self, - args: &'a str, - attachment_index: usize, - ctx: &serenity::Context, - msg: &serenity::Message, - ) -> Result< - (&'a str, usize, serenity::RoleId), - (Box, Option), - > { - let (args, string) = - pop_string(args).map_err(|_| (TooFewArguments::default().into(), None))?; - - if let Some(user_id) = string - .parse() - .ok() - .or_else(|| serenity::utils::parse_role_mention(&string)) - { - Ok((args.trim_start(), attachment_index, user_id)) - } else { - Err((InvalidRoleId::default().into(), Some(string))) + impl std::error::Error for $error_type {} + impl std::fmt::Display for $error_type { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + f.write_str(concat!( + "Enter a valid ", + stringify!($error_type), + " ID or a mention." + )) + } } - } -} - -#[async_trait::async_trait] -impl<'a> PopArgumentHack<'a, serenity::ChannelId> for &PhantomData { - async fn pop_from( - self, - args: &'a str, - attachment_index: usize, - ctx: &serenity::Context, - msg: &serenity::Message, - ) -> Result< - (&'a str, usize, serenity::ChannelId), - (Box, Option), - > { - let (args, string) = - pop_string(args).map_err(|_| (TooFewArguments::default().into(), None))?; - if let Some(user_id) = string - .parse() - .ok() - .or_else(|| serenity::utils::parse_channel_mention(&string)) - { - Ok((args.trim_start(), attachment_index, user_id)) - } else { - Err((InvalidChannelId::default().into(), Some(string))) + #[async_trait::async_trait] + impl<'a> PopArgumentHack<'a, $type> for &PhantomData<$type> { + async fn pop_from( + self, + args: &'a str, + attachment_index: usize, + ctx: &serenity::Context, + msg: &serenity::Message, + ) -> Result< + (&'a str, usize, $type), + (Box, Option), + > { + let (args, string) = + pop_string(args).map_err(|_| (TooFewArguments::default().into(), None))?; + + if let Some(parsed_id) = string + .parse() + .ok() + .or_else(|| serenity::utils::$parse_fn(&string)) + { + Ok((args.trim_start(), attachment_index, parsed_id)) + } else { + Err(($error_type::default().into(), Some(string))) + } + } } - } + }; } + +snowflake_pop_argument!(serenity::UserId, parse_user_mention, InvalidUserId); +snowflake_pop_argument!(serenity::ChannelId, parse_channel_mention, InvalidChannelId); +snowflake_pop_argument!(serenity::RoleId, parse_role_mention, InvalidRoleId); diff --git a/src/prefix_argument/mod.rs b/src/prefix_argument/mod.rs index 991c240ab8f..fdfa6e53471 100644 --- a/src/prefix_argument/mod.rs +++ b/src/prefix_argument/mod.rs @@ -125,45 +125,6 @@ impl std::fmt::Display for InvalidBool { } impl std::error::Error for InvalidBool {} -/// Error thrown when the user enters a string that cannot be parsed as a UserId. -#[derive(Default, Debug)] -pub struct InvalidUserId { - #[doc(hidden)] - pub __non_exhaustive: (), -} -impl std::fmt::Display for InvalidUserId { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - f.write_str("Enter a valid user's ID or a mention.") - } -} -impl std::error::Error for InvalidUserId {} - -/// Error thrown when the user enters a string that cannot be parsed as a RoleId. -#[derive(Default, Debug)] -pub struct InvalidRoleId { - #[doc(hidden)] - pub __non_exhaustive: (), -} -impl std::fmt::Display for InvalidRoleId { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - f.write_str("Enter a valid role's ID or a mention.") - } -} -impl std::error::Error for InvalidRoleId {} - -/// Error thrown when the user enters a string that cannot be parsed as a RoleId. -#[derive(Default, Debug)] -pub struct InvalidChannelId { - #[doc(hidden)] - pub __non_exhaustive: (), -} -impl std::fmt::Display for InvalidChannelId { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - f.write_str("Enter a valid channel's ID or a mention.") - } -} -impl std::error::Error for InvalidChannelId {} - #[cfg(test)] #[test] fn test_pop_string() {