#[cfg(all(feature = "model", feature = "utils"))]
use std::error::Error as StdError;
use std::fmt;
#[cfg(all(feature = "model", feature = "utils"))]
use std::str::FromStr;
use super::prelude::*;
#[cfg(all(feature = "model", feature = "utils"))]
use crate::utils;
pub trait Mentionable {
fn mention(&self) -> Mention;
}
#[derive(Clone, Copy, Debug)]
pub enum Mention {
Channel(ChannelId),
Role(RoleId),
User(UserId),
}
macro_rules! mention {
($i:ident: $($t:ty, $e:expr;)*) => {$(
impl From<$t> for Mention {
#[inline(always)]
fn from($i: $t) -> Self {
$e
}
}
)*};
}
mention!(value:
ChannelId, Mention::Channel(value);
RoleId, Mention::Role(value);
UserId, Mention::User(value);
);
impl fmt::Display for Mention {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match *self {
Mention::Channel(id) => f.write_fmt(format_args!("<#{id}>")),
Mention::Role(id) => f.write_fmt(format_args!("<@&{id}>")),
Mention::User(id) => f.write_fmt(format_args!("<@{id}>")),
}
}
}
#[cfg(all(feature = "model", feature = "utils"))]
#[derive(Debug)]
pub enum MentionParseError {
InvalidMention,
}
#[cfg(all(feature = "model", feature = "utils"))]
impl fmt::Display for MentionParseError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.write_str("invalid mention")
}
}
#[cfg(all(feature = "model", feature = "utils"))]
impl StdError for MentionParseError {}
#[cfg(all(feature = "model", feature = "utils"))]
impl FromStr for Mention {
type Err = MentionParseError;
fn from_str(s: &str) -> StdResult<Self, Self::Err> {
let m = if let Some(id) = utils::parse_channel_mention(s) {
id.mention()
} else if let Some(id) = utils::parse_role_mention(s) {
id.mention()
} else if let Some(id) = utils::parse_user_mention(s) {
id.mention()
} else {
return Err(MentionParseError::InvalidMention);
};
Ok(m)
}
}
impl<T> Mentionable for T
where
T: Into<Mention> + Copy,
{
fn mention(&self) -> Mention {
(*self).into()
}
}
macro_rules! mentionable {
($i:ident: $t:ty, $e:expr) => {
impl Mentionable for $t {
#[inline(always)]
fn mention(&self) -> Mention {
let $i = self;
$e.into()
}
}
};
}
#[cfg(feature = "model")]
mentionable!(value: Channel, value.id());
mentionable!(value: GuildChannel, value.id);
mentionable!(value: PrivateChannel, value.id);
mentionable!(value: Member, value.user.id);
mentionable!(value: CurrentUser, value.id);
mentionable!(value: User, value.id);
mentionable!(value: Role, value.id);
#[cfg(feature = "utils")]
#[cfg(test)]
mod test {
use crate::model::prelude::*;
#[test]
fn test_mention() {
let channel = Channel::Guild(GuildChannel {
id: ChannelId::new(4),
..Default::default()
});
let role = Role {
id: RoleId::new(2),
..Default::default()
};
let user = User {
id: UserId::new(6),
..Default::default()
};
let member = Member {
user: user.clone(),
..Default::default()
};
assert_eq!(ChannelId::new(1).mention().to_string(), "<#1>");
#[cfg(feature = "model")]
assert_eq!(channel.mention().to_string(), "<#4>");
assert_eq!(member.mention().to_string(), "<@6>");
assert_eq!(role.mention().to_string(), "<@&2>");
assert_eq!(role.id.mention().to_string(), "<@&2>");
assert_eq!(user.mention().to_string(), "<@6>");
assert_eq!(user.id.mention().to_string(), "<@6>");
}
}