#[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(Debug, Clone, Copy)]
pub enum Mention {
Channel(ChannelId),
Role(RoleId),
User(UserId),
Emoji(EmojiId, bool),
}
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);
EmojiId, Mention::Emoji(value, false);
(EmojiId, bool), Mention::Emoji(value.0, value.1);
);
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.0)),
Mention::Role(id) => f.write_fmt(format_args!("<@&{}>", id.0)),
Mention::User(id) => f.write_fmt(format_args!("<@{}>", id.0)),
Mention::Emoji(id, animated) => {
f.write_fmt(format_args!("<{}:omitted:{}>", if animated { "a" } else { "" }, id.0,))
},
}
}
}
#[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(s) {
ChannelId(id).mention()
} else if let Some(id) = utils::parse_role(s) {
RoleId(id).mention()
} else if let Some(id) = utils::parse_username(s) {
UserId(id).mention()
} else if let Some(emoji_ident) = utils::parse_emoji(s) {
emoji_ident.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:
ChannelCategory, value.id;
GuildChannel, value.id;
PrivateChannel, value.id;
CurrentUser, value.id;
Member, value.user.id;
User, value.id;
Role, value.id;
Emoji, (value.id, value.animated);
EmojiIdentifier, (value.id, value.animated);
);
#[cfg(feature = "utils")]
#[cfg(test)]
mod test {
use crate::model::prelude::*;
use crate::utils::Colour;
#[test]
fn test_mention() {
let channel = Channel::Guild(GuildChannel {
bitrate: None,
parent_id: None,
guild_id: GuildId(1),
kind: ChannelType::Text,
id: ChannelId(4),
last_message_id: None,
last_pin_timestamp: None,
name: "a".to_string(),
permission_overwrites: vec![],
position: 1,
topic: None,
user_limit: None,
nsfw: false,
rate_limit_per_user: Some(0),
rtc_region: None,
video_quality_mode: None,
message_count: None,
member_count: None,
thread_metadata: None,
member: None,
default_auto_archive_duration: None,
});
let emoji = Emoji {
animated: false,
available: true,
id: EmojiId(5),
name: "a".to_string(),
managed: true,
require_colons: true,
roles: vec![],
user: None,
};
let role = Role {
id: RoleId(2),
guild_id: GuildId(1),
colour: Colour::ROSEWATER,
hoist: false,
managed: false,
mentionable: false,
name: "fake role".to_string(),
permissions: Permissions::empty(),
position: 1,
tags: RoleTags::default(),
icon: None,
unicode_emoji: None,
};
let user = User {
id: UserId(6),
avatar: None,
bot: false,
discriminator: 4132,
name: "fake".to_string(),
public_flags: None,
banner: None,
accent_colour: None,
};
let member = Member {
deaf: false,
guild_id: GuildId(2),
joined_at: None,
mute: false,
nick: None,
roles: vec![],
user: user.clone(),
pending: false,
premium_since: None,
permissions: None,
avatar: None,
communication_disabled_until: None,
};
assert_eq!(ChannelId(1).mention().to_string(), "<#1>");
#[cfg(feature = "model")]
assert_eq!(channel.mention().to_string(), "<#4>");
assert_eq!(emoji.mention().to_string(), "<:omitted:5>");
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>");
}
}