Skip to content

Commit

Permalink
Write macro to deduplicate
Browse files Browse the repository at this point in the history
  • Loading branch information
jamesbt365 committed Oct 22, 2024
1 parent 5d38cd7 commit 533571b
Show file tree
Hide file tree
Showing 2 changed files with 48 additions and 117 deletions.
126 changes: 48 additions & 78 deletions src/prefix_argument/argument_trait.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down Expand Up @@ -139,83 +136,56 @@ impl<'a> PopArgumentHack<'a, serenity::Attachment> for &PhantomData<serenity::At
}
}

#[async_trait::async_trait]
impl<'a> PopArgumentHack<'a, serenity::UserId> for &PhantomData<serenity::UserId> {
async fn pop_from(
self,
args: &'a str,
attachment_index: usize,
ctx: &serenity::Context,
msg: &serenity::Message,
) -> Result<
(&'a str, usize, serenity::UserId),
(Box<dyn std::error::Error + Send + Sync>, Option<String>),
> {
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<serenity::RoleId> {
async fn pop_from(
self,
args: &'a str,
attachment_index: usize,
ctx: &serenity::Context,
msg: &serenity::Message,
) -> Result<
(&'a str, usize, serenity::RoleId),
(Box<dyn std::error::Error + Send + Sync>, Option<String>),
> {
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<serenity::ChannelId> {
async fn pop_from(
self,
args: &'a str,
attachment_index: usize,
ctx: &serenity::Context,
msg: &serenity::Message,
) -> Result<
(&'a str, usize, serenity::ChannelId),
(Box<dyn std::error::Error + Send + Sync>, Option<String>),
> {
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<dyn std::error::Error + Send + Sync>, Option<String>),
> {
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);
39 changes: 0 additions & 39 deletions src/prefix_argument/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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() {
Expand Down

0 comments on commit 533571b

Please sign in to comment.