From 1a99c92271c31e1b27964e69f94b261be614c180 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Emil=20Gardstr=C3=B6m?= Date: Sat, 3 Dec 2022 06:59:26 +0100 Subject: [PATCH] support v2 emotes --- src/maybe_owned/mod.rs | 3 +++ src/messages/privmsg.rs | 2 +- src/twitch/emotes.rs | 33 +++++++++++++++++++++++++-------- 3 files changed, 29 insertions(+), 9 deletions(-) diff --git a/src/maybe_owned/mod.rs b/src/maybe_owned/mod.rs index a2674a4..2dead15 100644 --- a/src/maybe_owned/mod.rs +++ b/src/maybe_owned/mod.rs @@ -19,6 +19,7 @@ pub use maybe_owned_index::MaybeOwnedIndex; /// /// This only exposed for people to extend messages themselves. #[cfg_attr(feature = "serde", derive(::serde::Serialize), serde(untagged))] +#[derive(Hash)] pub enum MaybeOwned<'a> { /// Owned variant, a `Box`. This usually means it has a `'static` lifetime Owned(Box), @@ -59,6 +60,8 @@ impl<'a> PartialEq for MaybeOwned<'a> { } } +impl<'a> Eq for MaybeOwned<'a> {} + impl<'a> PartialEq for MaybeOwned<'a> { fn eq(&self, other: &str) -> bool { self.as_ref() == other diff --git a/src/messages/privmsg.rs b/src/messages/privmsg.rs index 4de6b94..b61f0ce 100644 --- a/src/messages/privmsg.rs +++ b/src/messages/privmsg.rs @@ -55,7 +55,7 @@ pub struct EmotesIter<'a> { } impl<'a> Iterator for EmotesIter<'a> { - type Item = Emotes; + type Item = Emotes<'a>; fn next(&mut self) -> Option { if let Some(item) = self.items.as_mut()?.next() { diff --git a/src/twitch/emotes.rs b/src/twitch/emotes.rs index 98a32ad..996b486 100644 --- a/src/twitch/emotes.rs +++ b/src/twitch/emotes.rs @@ -1,5 +1,7 @@ use std::ops::Range; +use crate::maybe_owned::MaybeOwned; + /** Emotes are little pictograms used in-line in Twitch messages @@ -12,26 +14,26 @@ They are presented (to the irc connection) in a `id:range1,range2/id2:range1,..` */ #[derive(Debug, Clone, PartialEq, Eq, Hash)] #[cfg_attr(feature = "serde", derive(::serde::Serialize, ::serde::Deserialize))] -pub struct Emotes { - /// This emote id, e.g. `Kappa = 25` - pub id: usize, +pub struct Emotes<'a> { + /// This emote id, e.g. `Kappa = 25` + pub id: MaybeOwned<'a>, /// A list of [Range] in the message where this emote is found /// /// [Range]: https://doc.rust-lang.org/std/ops/struct.Range.html pub ranges: Vec>, } -impl Emotes { +impl<'a> Emotes<'a> { /// Parse emotes from a string, returning an iterator over each emote - pub fn parse(input: &str) -> impl Iterator + '_ { + pub fn parse(input: &'a str) -> impl Iterator> + 'a { input.split_terminator('/').filter_map(Self::parse_item) } /// Parse single emote - pub fn parse_item(item: &str) -> Option { + pub fn parse_item(item: &'a str) -> Option { get_parts(item, ':').and_then(|(head, tail)| { let emotes = Self { - id: head.parse().ok()?, + id: head.into(), ranges: get_ranges(tail).collect(), }; emotes.into() @@ -39,6 +41,16 @@ impl Emotes { } } +impl<'a> crate::IntoOwned<'a> for Emotes<'a> { + type Output = Emotes<'static>; + fn into_owned(self) -> Self::Output { + Emotes { + id: self.id.into_owned(), + ranges: self.ranges, + } + } +} + #[inline] fn get_parts(input: &str, sep: char) -> Option<(&str, &str)> { let mut split = input.split_terminator(sep); @@ -64,10 +76,11 @@ mod tests { macro_rules! emote { ($id:expr, $($r:expr),* $(,)?) => { Emotes { - id: $id, + id: $id.to_string().into(), ranges: vec![$($r),*] } }; + } let inputs = &[ @@ -95,6 +108,10 @@ mod tests { "33:0-7/25:9-13,15-19", vec![emote!(33, (0..7)), emote!(25, (9..13), (15..19))], ), + ( + "emotesv2_4c3b4ed516de493bbcd2df2f5d450f49:0-25", + vec![emote!("emotesv2_4c3b4ed516de493bbcd2df2f5d450f49", (0..25))], + ), ]; for (input, expect) in inputs {