use std::borrow::Cow;
use crate::Tags;
#[derive(Clone, Debug, PartialEq, PartialOrd, Eq, Ord, Hash)]
#[cfg_attr(feature = "serde", derive(::serde::Serialize, ::serde::Deserialize))]
pub struct Emote<'a> {
pub id: Cow<'a, str>,
pub name: Cow<'a, str>,
pub byte_pos: (usize, usize),
}
impl<'a> Emote<'a> {
pub fn from_tags<'t: 'a>(
tags: &'t Tags<'a>,
data: &'a str,
) -> impl Iterator<Item = Emote<'a>> + 't {
tags.get("emotes")
.into_iter()
.flat_map(|input| parse_emotes(input, data))
}
}
pub fn parse_emotes<'a>(input: &'a str, data: &'a str) -> impl Iterator<Item = Emote<'a>> + 'a {
fn substr(data: &str, start: &mut usize, end: &mut usize) -> Cow<'static, str> {
let (s, e) = (*start, *end);
*start = data.chars().map(|s| s.len_utf8()).take(s).sum();
*end = data.chars().map(|s| s.len_utf8()).take(e).sum();
data.chars().skip(s).take(e).collect()
}
input
.split('/')
.flat_map(|s| s.split_once(':'))
.flat_map(|(emote, range)| {
range
.split(',')
.flat_map(|c| c.split_once('-').map(|(s, e)| (s.parse(), e.parse())))
.flat_map(|(start, end)| Some((start.ok()?, end.ok()?)))
.zip(std::iter::repeat(emote))
.map(|((start, end), kind): ((usize, usize), _)| (kind, (start, end - start + 1)))
})
.map(|(emote, (mut start, end))| {
let (end, start) = (&mut (end + start), &mut start);
Emote {
id: Cow::from(emote),
name: substr(data, start, end),
byte_pos: (*start, *end),
}
})
}
impl<'a> std::ops::Index<&Emote<'a>> for str {
type Output = str;
fn index(&self, index: &Emote<'a>) -> &Self::Output {
let (s, e) = index.byte_pos;
&self[s..e]
}
}