serenity/model/
mention.rs1#[cfg(all(feature = "model", feature = "utils"))]
2use std::error::Error as StdError;
3use std::fmt;
4#[cfg(all(feature = "model", feature = "utils"))]
5use std::str::FromStr;
6
7use super::prelude::*;
8#[cfg(all(feature = "model", feature = "utils"))]
9use crate::utils;
10
11pub trait Mentionable {
13 fn mention(&self) -> Mention;
61}
62
63#[derive(Clone, Copy, Debug)]
85pub enum Mention {
86 Channel(ChannelId),
87 Role(RoleId),
88 User(UserId),
89}
90
91macro_rules! mention {
92 ($i:ident: $($t:ty, $e:expr;)*) => {$(
93 impl From<$t> for Mention {
94 #[inline(always)]
95 fn from($i: $t) -> Self {
96 $e
97 }
98 }
99 )*};
100}
101
102mention!(value:
103 ChannelId, Mention::Channel(value);
104 RoleId, Mention::Role(value);
105 UserId, Mention::User(value);
106);
107
108impl fmt::Display for Mention {
109 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
110 match *self {
111 Mention::Channel(id) => f.write_fmt(format_args!("<#{id}>")),
112 Mention::Role(id) => f.write_fmt(format_args!("<@&{id}>")),
113 Mention::User(id) => f.write_fmt(format_args!("<@{id}>")),
114 }
115 }
116}
117
118#[cfg(all(feature = "model", feature = "utils"))]
119#[derive(Debug)]
120pub enum MentionParseError {
121 InvalidMention,
122}
123
124#[cfg(all(feature = "model", feature = "utils"))]
125impl fmt::Display for MentionParseError {
126 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
127 f.write_str("invalid mention")
128 }
129}
130
131#[cfg(all(feature = "model", feature = "utils"))]
132impl StdError for MentionParseError {}
133
134#[cfg(all(feature = "model", feature = "utils"))]
135impl FromStr for Mention {
136 type Err = MentionParseError;
137
138 fn from_str(s: &str) -> StdResult<Self, Self::Err> {
139 let m = if let Some(id) = utils::parse_channel_mention(s) {
140 id.mention()
141 } else if let Some(id) = utils::parse_role_mention(s) {
142 id.mention()
143 } else if let Some(id) = utils::parse_user_mention(s) {
144 id.mention()
145 } else {
146 return Err(MentionParseError::InvalidMention);
147 };
148
149 Ok(m)
150 }
151}
152
153impl<T> Mentionable for T
154where
155 T: Into<Mention> + Copy,
156{
157 fn mention(&self) -> Mention {
158 (*self).into()
159 }
160}
161
162macro_rules! mentionable {
163 ($i:ident: $t:ty, $e:expr) => {
164 impl Mentionable for $t {
165 #[inline(always)]
166 fn mention(&self) -> Mention {
167 let $i = self;
168 $e.into()
169 }
170 }
171 };
172}
173
174#[cfg(feature = "model")]
175mentionable!(value: Channel, value.id());
176
177mentionable!(value: GuildChannel, value.id);
178mentionable!(value: PrivateChannel, value.id);
179mentionable!(value: Member, value.user.id);
180mentionable!(value: CurrentUser, value.id);
181mentionable!(value: User, value.id);
182mentionable!(value: Role, value.id);
183
184#[cfg(feature = "utils")]
185#[cfg(test)]
186mod test {
187 use crate::model::prelude::*;
188
189 #[test]
190 fn test_mention() {
191 let channel = Channel::Guild(GuildChannel {
192 id: ChannelId::new(4),
193 ..Default::default()
194 });
195 let role = Role {
196 id: RoleId::new(2),
197 ..Default::default()
198 };
199 let user = User {
200 id: UserId::new(6),
201 ..Default::default()
202 };
203 let member = Member {
204 user: user.clone(),
205 ..Default::default()
206 };
207
208 assert_eq!(ChannelId::new(1).mention().to_string(), "<#1>");
209 #[cfg(feature = "model")]
210 assert_eq!(channel.mention().to_string(), "<#4>");
211 assert_eq!(member.mention().to_string(), "<@6>");
212 assert_eq!(role.mention().to_string(), "<@&2>");
213 assert_eq!(role.id.mention().to_string(), "<@&2>");
214 assert_eq!(user.mention().to_string(), "<@6>");
215 assert_eq!(user.id.mention().to_string(), "<@6>");
216 }
217}