use super::ParseMention;
use std::{iter::Iterator, marker::PhantomData, str::CharIndices};
#[derive(Clone, Debug)]
pub struct MentionIter<'a, T> {
buf: &'a str,
chars: CharIndices<'a>,
phantom: PhantomData<T>,
}
impl<'a, T> MentionIter<'a, T> {
#[must_use]
pub(in crate::parse) fn new(buf: &'a str) -> Self {
let chars = buf.char_indices();
Self {
buf,
chars,
phantom: PhantomData,
}
}
#[must_use]
pub const fn as_str(&self) -> &'a str {
self.buf
}
}
impl<'a, T: ParseMention> Iterator for MentionIter<'a, T> {
type Item = (T, usize, usize);
fn next(&mut self) -> Option<Self::Item> {
loop {
let start = match self.chars.next()? {
(idx, '<') => idx,
_ => continue,
};
let mut found = false;
for sigil in T::SIGILS {
if self.chars.as_str().starts_with(sigil) {
found = true;
for _ in 0..sigil.chars().count() {
self.chars.next();
}
}
}
if !found {
continue;
}
let end = if let Some((idx, _)) = self.chars.find(|c| c.1 == '>') {
idx
} else {
continue;
};
let buf = self.buf.get(start..=end)?;
if let Ok(id) = T::parse(buf) {
return Some((id, start, end));
}
}
}
}
#[cfg(test)]
mod tests {
use crate::timestamp::{Timestamp, TimestampStyle};
use super::{
super::{MentionType, ParseMention},
MentionIter,
};
use static_assertions::{assert_impl_all, assert_obj_safe};
use std::fmt::Debug;
use twilight_model::id::{
marker::{ChannelMarker, EmojiMarker, RoleMarker, UserMarker},
Id,
};
assert_impl_all!(MentionIter<'_, Id<ChannelMarker>>: Clone, Debug, Iterator, Send, Sync);
assert_impl_all!(MentionIter<'_, Id<EmojiMarker>>: Clone, Debug, Iterator, Send, Sync);
assert_impl_all!(MentionIter<'_, MentionType>: Clone, Debug, Iterator, Send, Sync);
assert_impl_all!(MentionIter<'_, Id<RoleMarker>>: Clone, Debug, Iterator, Send, Sync);
assert_impl_all!(MentionIter<'_, Id<UserMarker>>: Clone, Debug, Iterator, Send, Sync);
assert_obj_safe!(
MentionIter<'_, Id<ChannelMarker>>,
MentionIter<'_, Id<EmojiMarker>>,
MentionIter<'_, MentionType>,
MentionIter<'_, Id<RoleMarker>>,
MentionIter<'_, Id<UserMarker>>,
);
#[test]
fn test_iter_channel_id() {
let mut iter = Id::<ChannelMarker>::iter("<#123>");
assert_eq!(Id::new(123), iter.next().unwrap().0);
assert!(iter.next().is_none());
}
#[test]
fn test_iter_multiple_ids() {
let buf = "one <@123>two<#456><@789> ----";
let mut iter = Id::<UserMarker>::iter(buf);
assert_eq!(Id::new(123), iter.next().unwrap().0);
let (mention, start, end) = iter.next().unwrap();
assert_eq!(Id::new(789), mention);
assert_eq!(19, start);
assert_eq!(24, end);
assert!(iter.next().is_none());
}
#[test]
fn test_iter_emoji_ids() {
let mut iter = Id::<EmojiMarker>::iter("some <:name:123> emojis <:emoji:456>");
assert_eq!(Id::new(123), iter.next().unwrap().0);
assert_eq!(Id::new(456), iter.next().unwrap().0);
assert!(iter.next().is_none());
}
#[test]
fn test_iter_mention_type() {
let mut iter = MentionType::iter("<#12><:name:34><@&56><@78>");
assert_eq!(MentionType::Channel(Id::new(12)), iter.next().unwrap().0);
assert_eq!(MentionType::Emoji(Id::new(34)), iter.next().unwrap().0);
assert_eq!(MentionType::Role(Id::new(56)), iter.next().unwrap().0);
assert_eq!(MentionType::User(Id::new(78)), iter.next().unwrap().0);
assert!(iter.next().is_none());
}
#[test]
fn test_iter_mention_type_with_timestamp() {
let mut iter = MentionType::iter("<#12> <t:34> <t:56:d>");
assert_eq!(MentionType::Channel(Id::new(12)), iter.next().unwrap().0);
assert_eq!(
MentionType::Timestamp(Timestamp::new(34, None)),
iter.next().unwrap().0
);
assert_eq!(
MentionType::Timestamp(Timestamp::new(56, Some(TimestampStyle::ShortDate))),
iter.next().unwrap().0
);
assert!(iter.next().is_none());
}
#[test]
fn test_iter_role_ids() {
let mut iter = Id::<RoleMarker>::iter("some <@&123> roles <@&456>");
assert_eq!(Id::new(123), iter.next().unwrap().0);
assert_eq!(Id::new(456), iter.next().unwrap().0);
assert!(iter.next().is_none());
}
#[test]
fn test_iter_timestamps() {
let mut iter = Timestamp::iter("some <t:123> roles <t:456:t>");
assert_eq!(Timestamp::new(123, None), iter.next().unwrap().0);
assert_eq!(
Timestamp::new(456, Some(TimestampStyle::ShortTime)),
iter.next().unwrap().0
);
assert!(iter.next().is_none());
}
#[test]
fn test_iter_user_ids() {
let mut iter = Id::<UserMarker>::iter("some <@123>users<@456>");
assert_eq!(Id::new(123), iter.next().unwrap().0);
assert_eq!(Id::new(456), iter.next().unwrap().0);
assert!(iter.next().is_none());
}
#[test]
fn test_iter_no_id() {
let mention = "this is not <# actually a mention";
let mut iter = Id::<ChannelMarker>::iter(mention);
assert!(iter.next().is_none());
}
#[test]
fn test_iter_ignores_other_types() {
let mention = "<#123> <:name:456> <@&789>";
let mut iter = Id::<UserMarker>::iter(mention);
assert!(iter.next().is_none());
}
#[test]
fn test_iter_as_str() {
let buf = "a buf";
let mut iter = Id::<RoleMarker>::iter(buf);
assert_eq!(buf, iter.as_str());
assert!(iter.next().is_none());
assert_eq!(buf, iter.as_str());
}
}