1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161
//! Parse mentions out of strings.
//!
//! Included is a trait over select IDs that can be mentioned and an iterator
//! to lazily parse mentions.
//!
//! There is also the [`MentionType`]: it's an enum wrapping all possible types
//! of mentions and works just like the individual IDs and [`Timestamp`].
//!
//! While the syntax of mentions will be validated and the IDs within them
//! parsed, they won't be validated as being proper snowflakes or as real IDs in
//! use.
//!
//! # Examples
//!
//! Parse IDs out of strings that you know is just a mention:
//!
//! ```
//! use twilight_mention::ParseMention;
//! use twilight_model::id::{
//! marker::{ChannelMarker, EmojiMarker, RoleMarker},
//! Id,
//! };
//!
//! # fn main() -> Result<(), Box<dyn std::error::Error>> {
//! assert_eq!(Id::<EmojiMarker>::new(123), Id::parse("<:name:123>")?);
//! assert_eq!(Id::<RoleMarker>::new(456), Id::parse("<@&456>")?);
//! assert!(Id::<ChannelMarker>::parse("<#notamention>").is_err());
//! # Ok(()) }
//! ```
//!
//! Iterate over the user mentions in a buffer:
//!
//! ```
//! use twilight_mention::ParseMention;
//! use twilight_model::id::{marker::UserMarker, Id};
//!
//! let mut iter = Id::<UserMarker>::iter("these <@123> are <#456> mentions <@789>");
//! assert!(matches!(iter.next(), Some((user, _, _)) if user.get() == 123));
//! assert!(matches!(iter.next(), Some((user, _, _)) if user.get() == 789));
//! assert!(iter.next().is_none());
//! ```
//!
//! Parse a timestamp:
//!
//! ```
//! # fn main() -> Result<(), Box<dyn std::error::Error>> {
//! use twilight_mention::{
//! parse::ParseMention,
//! timestamp::{Timestamp, TimestampStyle},
//! };
//!
//! let expected_timestamp = Timestamp::new(1_600_000_000, Some(TimestampStyle::RelativeTime));
//! assert_eq!(expected_timestamp, Timestamp::parse("<t:1600000000:R>")?);
//! # Ok(()) }
//! ```
//!
//! [`Timestamp`]: crate::timestamp::Timestamp
mod error;
mod r#impl;
mod iter;
use crate::{timestamp::Timestamp, Mention};
pub use self::{
error::{ParseMentionError, ParseMentionErrorType},
iter::MentionIter,
r#impl::ParseMention,
};
use std::fmt::{Display, Formatter, Result as FmtResult};
use twilight_model::id::{
marker::{ChannelMarker, EmojiMarker, RoleMarker, UserMarker},
Id,
};
/// Any type of mention.
///
/// Contains variants for every possible kind of mention. Can be used with
/// [`ParseMention`] and iterated over just like any other mention.
///
/// # Examples
///
/// Parse any type of mention out of a string:
///
/// ```
/// use twilight_mention::{
/// parse::{MentionType, ParseMention},
/// timestamp::Timestamp,
/// };
/// use twilight_model::id::{
/// marker::{ChannelMarker, RoleMarker, UserMarker},
/// Id,
/// };
///
/// # fn main() -> Result<(), Box<dyn std::error::Error>> {
/// assert_eq!(
/// MentionType::Channel(Id::<ChannelMarker>::new(123)),
/// MentionType::parse("<#123>")?,
/// );
/// assert_eq!(
/// MentionType::Role(Id::<RoleMarker>::new(123)),
/// MentionType::parse("<@&123>")?,
/// );
///
/// let timestamp = Timestamp::new(123, None);
/// assert_eq!(
/// MentionType::Timestamp(timestamp),
/// MentionType::parse("<t:123>")?
/// );
/// # Ok(()) }
/// ```
///
/// Iterate over all types of mentions in a buffer:
///
/// ```
/// use twilight_mention::{
/// parse::{MentionType, ParseMention},
/// timestamp::Timestamp,
/// };
///
/// let buf = "channel <#12> emoji <:name:34> role <@&56> timestamp <t:1624047978> user <@78>";
///
/// let mut iter = MentionType::iter(buf);
/// assert!(matches!(iter.next(), Some((MentionType::Channel(channel), _, _)) if channel.get() == 12));
/// assert!(matches!(iter.next(), Some((MentionType::Emoji(emoji), _, _)) if emoji.get() == 34));
/// assert!(matches!(iter.next(), Some((MentionType::Role(role), _, _)) if role.get() == 56));
/// assert!(matches!(
/// iter.next(),
/// Some((MentionType::Timestamp(timestamp), _, _))
/// if timestamp.unix() == 1_624_047_978 && timestamp.style().is_none()
/// ));
/// assert!(matches!(iter.next(), Some((MentionType::User(user), _, _)) if user.get() == 78));
/// assert!(iter.next().is_none());
/// ```
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
#[non_exhaustive]
pub enum MentionType {
/// Channel mention.
Channel(Id<ChannelMarker>),
/// Emoji mention.
Emoji(Id<EmojiMarker>),
/// Role mention.
Role(Id<RoleMarker>),
/// Timestamp mention.
Timestamp(Timestamp),
/// User mention.
User(Id<UserMarker>),
}
impl Display for MentionType {
fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult {
match self {
Self::Channel(id) => Display::fmt(id, f),
Self::Emoji(id) => Display::fmt(id, f),
Self::Role(id) => Display::fmt(id, f),
Self::Timestamp(timestamp) => Display::fmt(×tamp.mention(), f),
Self::User(id) => Display::fmt(id, f),
}
}
}