use super::{
is_not_empty, maybe_clone, maybe_unescape, parse_badges, split_comma, Badge, MessageParseError,
};
use crate::irc::{Command, IrcMessageRef, Tag};
use std::borrow::Cow;
#[derive(Clone, Debug, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct GlobalUserState<'src> {
#[cfg_attr(feature = "serde", serde(borrow))]
id: Cow<'src, str>,
#[cfg_attr(feature = "serde", serde(borrow))]
name: Cow<'src, str>,
#[cfg_attr(feature = "serde", serde(borrow))]
badges: Vec<Badge<'src>>,
#[cfg_attr(feature = "serde", serde(borrow))]
emote_sets: Vec<Cow<'src, str>>,
#[cfg_attr(feature = "serde", serde(borrow))]
color: Option<Cow<'src, str>>,
}
generate_getters! {
<'src> for GlobalUserState<'src> as self {
id -> &str = self.id.as_ref(),
name -> Cow<'src, str> = maybe_unescape(self.name.clone()),
badges -> impl DoubleEndedIterator<Item = &Badge<'src>> + ExactSizeIterator
= self.badges.iter(),
num_badges -> usize = self.badges.len(),
emote_sets -> impl DoubleEndedIterator<Item = &str> + ExactSizeIterator
= self.emote_sets.iter().map(|v| v.as_ref()),
num_emote_sets -> usize = self.emote_sets.len(),
color -> Option<&str> = self.color.as_deref(),
}
}
impl<'src> GlobalUserState<'src> {
fn parse(message: IrcMessageRef<'src>) -> Option<Self> {
if message.command() != Command::GlobalUserState {
return None;
}
Some(GlobalUserState {
id: message.tag(Tag::UserId)?.into(),
name: message.tag(Tag::DisplayName)?.into(),
badges: message
.tag(Tag::Badges)
.zip(message.tag(Tag::BadgeInfo))
.map(|(badges, badge_info)| parse_badges(badges, badge_info))
.unwrap_or_default(),
emote_sets: message
.tag(Tag::EmoteSets)
.map(split_comma)
.map(|i| i.map(Cow::Borrowed))
.map(Iterator::collect)
.unwrap_or_default(),
color: message
.tag(Tag::Color)
.filter(is_not_empty)
.map(Cow::Borrowed),
})
}
pub fn into_owned(self) -> GlobalUserState<'static> {
GlobalUserState {
id: maybe_clone(self.id),
name: maybe_clone(self.name),
badges: self.badges.into_iter().map(Badge::into_owned).collect(),
emote_sets: self.emote_sets.into_iter().map(maybe_clone).collect(),
color: self.color.map(maybe_clone),
}
}
}
impl<'src> super::FromIrc<'src> for GlobalUserState<'src> {
#[inline]
fn from_irc(message: IrcMessageRef<'src>) -> Result<Self, MessageParseError> {
Self::parse(message).ok_or(MessageParseError)
}
}
impl<'src> From<GlobalUserState<'src>> for super::Message<'src> {
fn from(msg: GlobalUserState<'src>) -> Self {
super::Message::GlobalUserState(msg)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn parse_globaluserstate() {
assert_irc_snapshot!(GlobalUserState, "@badge-info=;badges=;color=;display-name=randers811;emote-sets=0;user-id=553170741;user-type= :tmi.twitch.tv GLOBALUSERSTATE");
}
#[cfg(feature = "serde")]
#[test]
fn roundtrip_globaluserstate() {
assert_irc_roundtrip!(GlobalUserState, "@badge-info=;badges=;color=;display-name=randers811;emote-sets=0;user-id=553170741;user-type= :tmi.twitch.tv GLOBALUSERSTATE");
}
}