use super::{maybe_clone, parse_bool, MessageParseError};
use crate::irc::{Command, IrcMessageRef, Tag};
use std::borrow::Cow;
use std::time::Duration;
#[derive(Clone, Debug, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct RoomState<'src> {
#[cfg_attr(feature = "serde", serde(borrow))]
channel: Cow<'src, str>,
#[cfg_attr(feature = "serde", serde(borrow))]
channel_id: Cow<'src, str>,
emote_only: Option<bool>,
followers_only: Option<FollowersOnly>,
r9k: Option<bool>,
slow: Option<Duration>,
subs_only: Option<bool>,
}
generate_getters! {
<'src> for RoomState<'src> as self {
channel -> &str = self.channel.as_ref(),
channel_id -> &str = self.channel_id.as_ref(),
emote_only -> Option<bool>,
followers_only -> Option<FollowersOnly>,
r9k -> Option<bool>,
slow -> Option<Duration>,
subs_only -> Option<bool>,
}
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
#[cfg_attr(
feature = "serde",
derive(serde::Serialize, serde::Deserialize),
serde(rename_all = "lowercase")
)]
pub enum FollowersOnly {
Disabled,
Enabled(Option<Duration>),
}
impl<'src> RoomState<'src> {
fn parse(message: IrcMessageRef<'src>) -> Option<Self> {
if message.command() != Command::RoomState {
return None;
}
Some(RoomState {
channel: message.channel()?.into(),
channel_id: message.tag(Tag::RoomId)?.into(),
emote_only: message.tag(Tag::EmoteOnly).map(parse_bool),
followers_only: message
.tag(Tag::FollowersOnly)
.and_then(|v| v.parse().ok())
.map(|n: i64| match n {
n if n > 0 => FollowersOnly::Enabled(Some(Duration::from_secs((n * 60) as u64))),
0 => FollowersOnly::Enabled(None),
_ => FollowersOnly::Disabled,
}),
r9k: message.tag(Tag::R9K).map(parse_bool),
slow: message
.tag(Tag::Slow)
.and_then(|v| v.parse().ok())
.map(Duration::from_secs),
subs_only: message.tag(Tag::SubsOnly).map(parse_bool),
})
}
pub fn into_owned(self) -> RoomState<'static> {
RoomState {
channel: maybe_clone(self.channel),
channel_id: maybe_clone(self.channel_id),
emote_only: self.emote_only,
followers_only: self.followers_only,
r9k: self.r9k,
slow: self.slow,
subs_only: self.subs_only,
}
}
}
impl<'src> super::FromIrc<'src> for RoomState<'src> {
#[inline]
fn from_irc(message: IrcMessageRef<'src>) -> Result<Self, MessageParseError> {
Self::parse(message).ok_or(MessageParseError)
}
}
impl<'src> From<RoomState<'src>> for super::Message<'src> {
fn from(msg: RoomState<'src>) -> Self {
super::Message::RoomState(msg)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn parse_room_state_basic_full() {
assert_irc_snapshot!(RoomState, "@emote-only=0;followers-only=-1;r9k=0;rituals=0;room-id=40286300;slow=0;subs-only=0 :tmi.twitch.tv ROOMSTATE #randers");
}
#[test]
fn parse_room_state_basic_full2() {
assert_irc_snapshot!(RoomState, "@emote-only=1;followers-only=0;r9k=1;rituals=0;room-id=40286300;slow=5;subs-only=1 :tmi.twitch.tv ROOMSTATE #randers");
}
#[test]
fn parse_room_state_followers_non_zero() {
assert_irc_snapshot!(RoomState, "@emote-only=1;followers-only=10;r9k=1;rituals=0;room-id=40286300;slow=5;subs-only=1 :tmi.twitch.tv ROOMSTATE #randers");
}
#[test]
fn parse_room_state_partial_1() {
assert_irc_snapshot!(
RoomState,
"@room-id=40286300;slow=5 :tmi.twitch.tv ROOMSTATE #randers"
);
}
#[test]
fn parse_room_state_partial_2() {
assert_irc_snapshot!(
RoomState,
"@emote-only=1;room-id=40286300 :tmi.twitch.tv ROOMSTATE #randers"
);
}
#[cfg(feature = "serde")]
#[test]
fn roundtrip_room_state_basic_full() {
assert_irc_roundtrip!(RoomState, "@emote-only=0;followers-only=-1;r9k=0;rituals=0;room-id=40286300;slow=0;subs-only=0 :tmi.twitch.tv ROOMSTATE #randers");
}
#[cfg(feature = "serde")]
#[test]
fn roundtrip_room_state_basic_full2() {
assert_irc_roundtrip!(RoomState, "@emote-only=1;followers-only=0;r9k=1;rituals=0;room-id=40286300;slow=5;subs-only=1 :tmi.twitch.tv ROOMSTATE #randers");
}
#[cfg(feature = "serde")]
#[test]
fn roundtrip_room_state_followers_non_zero() {
assert_irc_roundtrip!(RoomState, "@emote-only=1;followers-only=10;r9k=1;rituals=0;room-id=40286300;slow=5;subs-only=1 :tmi.twitch.tv ROOMSTATE #randers");
}
#[cfg(feature = "serde")]
#[test]
fn roundtrip_room_state_partial_1() {
assert_irc_roundtrip!(
RoomState,
"@room-id=40286300;slow=5 :tmi.twitch.tv ROOMSTATE #randers"
);
}
#[cfg(feature = "serde")]
#[test]
fn roundtrip_room_state_partial_2() {
assert_irc_roundtrip!(
RoomState,
"@emote-only=1;room-id=40286300 :tmi.twitch.tv ROOMSTATE #randers"
);
}
}