use super::expect::Expect as _;
use super::*;
use crate::{AsOwned, Parse};
parse! {
bare Raw {
raw,
tags,
prefix,
command,
args,
data
} => |msg: &'t Message<'t>| {
Ok(msg.clone())
}
}
impl<'a: 't, 't> Parse<&'a Message<'t>> for AllCommands<'t> {
fn parse(msg: &'a Message<'t>) -> Result<Self, InvalidMessage> {
let out = match &*msg.command {
"001" => IrcReady::parse(msg)?.into(),
"PING" => Ping::parse(msg)?.into(),
"PONG" => Pong::parse(msg)?.into(),
"376" => Ready::parse(msg)?.into(),
"353" => Names::parse(msg)?.into(),
"366" => Names::parse(msg)?.into(),
"JOIN" => Join::parse(msg)?.into(),
"PART" => Part::parse(msg)?.into(),
"PRIVMSG" => Privmsg::parse(msg)?.into(),
"CAP" => Cap::parse(msg)?.into(),
"HOSTARGET" => HostTarget::parse(msg)?.into(),
"GLOBALUSERSTATE" => GlobalUserState::parse(msg)?.into(),
"NOTICE" => Notice::parse(msg)?.into(),
"CLEARCHAT" => ClearChat::parse(msg)?.into(),
"CLEARMSG" => ClearMsg::parse(msg)?.into(),
"RECONNECT" => Reconnect::parse(msg)?.into(),
"ROOMSTATE" => RoomState::parse(msg)?.into(),
"USERNOTICE" => UserNotice::parse(msg)?.into(),
"USERSTATE" => UserState::parse(msg)?.into(),
"MODE" => Mode::parse(msg)?.into(),
_ => msg.clone().into(),
};
Ok(out)
}
}
parse! {
RoomState { tags, channel } => |msg: &'t Message<'t>| {
msg.expect_command("ROOMSTATE")?;
Ok(Self {
channel: msg.expect_arg(0)?,
tags: msg.tags.clone()
})
}
}
parse! {
UserNotice { tags, channel, message } => |msg: &'t Message<'t>| {
msg.expect_command("USERNOTICE")?;
let channel = msg.expect_arg(0)?;
Ok(Self {
tags: msg.tags.clone(),
channel,
message: msg.data.clone(),
})
}
}
parse! {
Names { name, channel, kind } => |msg: &'t Message<'t>| {
let kind = match &*msg.command {
"353" => {
let users = msg.expect_data()?.split_whitespace();
let users = users.map(Cow::Borrowed).collect();
NamesKind::Start {
users
}
}
"366" => {
NamesKind::End
}
unknown => return Err(InvalidMessage::InvalidCommand {
expected: "353 or 366".to_string(),
got: unknown.to_string()
})
};
let name = msg.expect_arg(0)?;
let channel = match msg.expect_arg(1)? {
d if d == "=" => msg.expect_arg(2)?,
channel => channel
};
Ok(Self {
name,
channel,
kind
})
}
}
parse! {
GlobalUserState {
user_id,
display_name,
color,
emote_sets,
badges
} => |msg: &'t Message<'t>| {
msg.expect_command("GLOBALUSERSTATE")?;
let user_id = msg
.tags
.get("user-id")
.cloned()
.expect("user-id attached to message");
let display_name = msg.tags.get("display-name").cloned();
let color = msg
.tags
.get("color")
.and_then(|s| s.parse().ok())
.clone()
.unwrap_or_default();
let emote_sets = msg
.tags
.get("emotes-set")
.map(|s| s.split(',').map(Into::into).collect())
.unwrap_or_else(|| vec![Cow::from("0")]);
let badges = msg
.tags
.get("badges")
.map(|s| s.split(',').filter_map(crate::Badge::parse).collect())
.unwrap_or_default();
Ok(Self {
user_id,
display_name,
color,
emote_sets,
badges,
})
}
}
parse! {
HostTarget { source, viewers, kind } => |msg: &'t Message<'t>| {
msg.expect_command("HOSTTARGET")?;
let source = msg.expect_arg(0)?;
let (kind, viewers) = if let Ok(target) = msg.expect_arg(1) {
let viewers = msg.expect_arg(2).ok().and_then(|data| data.parse().ok());
(HostTargetKind::Start { target }, viewers)
} else {
let data = msg.expect_data()?;
if !data.starts_with('-') {
return Err(InvalidMessage::ExpectedData);
}
let viewers = data.get(2..).and_then(|s| s.parse().ok());
(HostTargetKind::End, viewers)
};
Ok(Self {
source,
kind,
viewers,
})
}
}
parse! {
Cap { capability, acknowledged } => |msg: &'t Message<'t>| {
msg.expect_command("CAP")?;
let acknowledged = msg.expect_arg(1)? == "ACK";
let capability = msg.expect_data()?.clone();
Ok(Self {
capability,
acknowledged,
})
}
}
parse! {
ClearChat { tags, channel, name } => |msg: &'t Message<'t>| {
msg.expect_command("CLEARCHAT")?;
Ok(Self {
tags: msg.tags.clone(),
channel: msg.expect_arg(0)?,
name: msg.expect_data().ok().cloned(),
})
}
}
parse! {
ClearMsg { tags, channel, message } => |msg: &'t Message<'t>| {
msg.expect_command("CLEARMSG")?;
Ok(Self {
tags: msg.tags.clone(),
channel: msg.expect_arg(0)?,
message: msg.expect_data().ok().cloned(),
})
}
}
parse! {
IrcReady { nickname } => |msg: &'t Message<'t>| {
msg.expect_command("001")?;
msg.expect_arg(0).map(|nickname| Self { nickname })
}
}
parse! {
Join { name, channel } => |msg: &'t Message<'t>| {
msg.expect_command("JOIN")?;
Ok(Self {
name: msg.expect_nick()?,
channel: msg.expect_arg(0)?,
})
}
}
parse! {
Mode { channel, status, name,} => |msg: &'t Message<'t>| {
msg.expect_command("MODE")?;
let channel = msg.expect_arg(0)?;
let status = match msg.expect_arg(1)?.chars().next().unwrap() {
'+' => ModeStatus::Gained,
'-' => ModeStatus::Lost,
_ => unreachable!(),
};
let name = msg.expect_arg(2)?;
Ok(Self {
channel,
status,
name,
})
}
}
parse! {
Notice { tags, channel, message } => |msg: &'t Message<'t>| {
msg.expect_command("NOTICE")?;
Ok(Self {
tags: msg.tags.clone(),
channel: msg.expect_arg(0)?,
message: msg.expect_data()?.clone(),
})
}
}
parse! {
Part { name, channel } => |msg: &'t Message<'t>| {
msg.expect_command("PART")?;
Ok(Self {
name: msg.expect_nick()?,
channel: msg.expect_arg(0)?,
})
}
}
parse! {
Ping { token } => |msg: &'t Message<'t>| {
msg.expect_command("PING")?;
msg.expect_data().map(|token| Self { token: token.clone() })
}
}
parse! {
Pong { token } => |msg: &'t Message<'t>| {
msg.expect_command("PONG")?;
msg.expect_data().map(|token| Self { token: token.clone() })
}
}
parse! {
Privmsg { name, channel, data, tags, } => |msg: &'t Message<'t>| {
msg.expect_command("PRIVMSG")?;
Ok(Self {
name: msg.expect_nick()?,
channel: msg.expect_arg(0)?,
data: msg.expect_data()?.clone(),
tags: msg.tags.clone(),
})
}
}
parse! {
Ready { username } => |msg: &'t Message<'t>| {
msg.expect_command("376")?;
msg.expect_arg(0).map(|username| Self { username })
}
}
parse! {
Reconnect => |msg: &'t Message<'t>| {
msg.expect_command("RECONNECT").map(|_| Self{ })
}
}
parse! {
UserState { tags, channel } => |msg: &'t Message<'t>| {
msg.expect_command("USERSTATE")?;
msg.expect_arg(0).map(|channel| Self {
channel,
tags: msg.tags.clone(),
})
}
}