diff --git a/examples/build-bot.rs b/examples/build-bot.rs index 5228e1b..e3d808c 100644 --- a/examples/build-bot.rs +++ b/examples/build-bot.rs @@ -29,7 +29,7 @@ async fn main() -> irc::error::Result<()> { while let Some(message) = stream.next().await.transpose()? { match message.command { - Command::Response(Response::RPL_ISUPPORT, _, _) => { + Command::Response(Response::RPL_ISUPPORT, _) => { client.send_privmsg( "#commits", format!( diff --git a/irc-proto/src/command.rs b/irc-proto/src/command.rs index b0c4c8b..49c4a70 100644 --- a/irc-proto/src/command.rs +++ b/irc-proto/src/command.rs @@ -156,7 +156,7 @@ pub enum Command { /// SAQUIT nickname :comment SAQUIT(String, String), /// NICKSERV message - NICKSERV(String), + NICKSERV(Vec), /// CHANSERV message CHANSERV(String), /// OPERSERV message @@ -189,12 +189,7 @@ pub enum Command { // IRCv3.2 extensions /// METADATA target COMMAND [params] :[param] - METADATA( - String, - Option, - Option>, - Option, - ), + METADATA(String, Option, Option>), /// MONITOR command [nicklist] MONITOR(String, Option), /// BATCH (+/-)reference-tag [type [params]] @@ -204,27 +199,34 @@ pub enum Command { // Default option. /// An IRC response code with arguments and optional suffix. - Response(Response, Vec, Option), + Response(Response, Vec), /// A raw IRC command unknown to the crate. - Raw(String, Vec, Option), + Raw(String, Vec), } -fn stringify(cmd: &str, args: &[&str], suffix: Option<&str>) -> String { - let args = args.join(" "); - let sp = if args.is_empty() { "" } else { " " }; - match suffix { - Some(suffix) => format!("{}{}{} :{}", cmd, sp, args, suffix), - None => format!("{}{}{}", cmd, sp, args), +fn stringify(cmd: &str, args: &[&str]) -> String { + match args.split_last() { + Some((suffix, args)) => { + let args = args.join(" "); + let sp = if args.is_empty() { "" } else { " " }; + let co = if suffix.is_empty() || suffix.contains(' ') { + ":" + } else { + "" + }; + format!("{}{}{} {}{}", cmd, sp, args, co, suffix) + } + None => cmd.to_string(), } } impl<'a> From<&'a Command> for String { fn from(cmd: &'a Command) -> String { match *cmd { - Command::PASS(ref p) => stringify("PASS", &[], Some(p)), - Command::NICK(ref n) => stringify("NICK", &[], Some(n)), - Command::USER(ref u, ref m, ref r) => stringify("USER", &[u, m, "*"], Some(r)), - Command::OPER(ref u, ref p) => stringify("OPER", &[u], Some(p)), + Command::PASS(ref p) => stringify("PASS", &[p]), + Command::NICK(ref n) => stringify("NICK", &[n]), + Command::USER(ref u, ref m, ref r) => stringify("USER", &[u, m, "*", r]), + Command::OPER(ref u, ref p) => stringify("OPER", &[u, p]), Command::UserMODE(ref u, ref m) => format!( "MODE {}{}", u, @@ -235,17 +237,17 @@ impl<'a> From<&'a Command> for String { }) ), Command::SERVICE(ref n, ref r, ref d, ref t, ref re, ref i) => { - stringify("SERVICE", &[n, r, d, t, re], Some(i)) + stringify("SERVICE", &[n, r, d, t, re, i]) } - Command::QUIT(Some(ref m)) => stringify("QUIT", &[], Some(m)), - Command::QUIT(None) => stringify("QUIT", &[], None), - Command::SQUIT(ref s, ref c) => stringify("SQUIT", &[s], Some(c)), - Command::JOIN(ref c, Some(ref k), Some(ref n)) => stringify("JOIN", &[c, k], Some(n)), - Command::JOIN(ref c, Some(ref k), None) => stringify("JOIN", &[c, k], None), - Command::JOIN(ref c, None, Some(ref n)) => stringify("JOIN", &[c], Some(n)), - Command::JOIN(ref c, None, None) => stringify("JOIN", &[c], None), - Command::PART(ref c, Some(ref m)) => stringify("PART", &[c], Some(m)), - Command::PART(ref c, None) => stringify("PART", &[c], None), + Command::QUIT(Some(ref m)) => stringify("QUIT", &[m]), + Command::QUIT(None) => stringify("QUIT", &[]), + Command::SQUIT(ref s, ref c) => stringify("SQUIT", &[s, c]), + Command::JOIN(ref c, Some(ref k), Some(ref n)) => stringify("JOIN", &[c, k, n]), + Command::JOIN(ref c, Some(ref k), None) => stringify("JOIN", &[c, k]), + Command::JOIN(ref c, None, Some(ref n)) => stringify("JOIN", &[c, n]), + Command::JOIN(ref c, None, None) => stringify("JOIN", &[c]), + Command::PART(ref c, Some(ref m)) => stringify("PART", &[c, m]), + Command::PART(ref c, None) => stringify("PART", &[c]), Command::ChannelMODE(ref u, ref m) => format!( "MODE {}{}", u, @@ -255,173 +257,133 @@ impl<'a> From<&'a Command> for String { acc }) ), - Command::TOPIC(ref c, Some(ref t)) => stringify("TOPIC", &[c], Some(t)), - Command::TOPIC(ref c, None) => stringify("TOPIC", &[c], None), - Command::NAMES(Some(ref c), Some(ref t)) => stringify("NAMES", &[c], Some(t)), - Command::NAMES(Some(ref c), None) => stringify("NAMES", &[c], None), - Command::NAMES(None, _) => stringify("NAMES", &[], None), - Command::LIST(Some(ref c), Some(ref t)) => stringify("LIST", &[c], Some(t)), - Command::LIST(Some(ref c), None) => stringify("LIST", &[c], None), - Command::LIST(None, _) => stringify("LIST", &[], None), - Command::INVITE(ref n, ref c) => stringify("INVITE", &[n, c], None), - Command::KICK(ref c, ref n, Some(ref r)) => stringify("KICK", &[c, n], Some(r)), - Command::KICK(ref c, ref n, None) => stringify("KICK", &[c, n], None), - Command::PRIVMSG(ref t, ref m) => stringify("PRIVMSG", &[t], Some(m)), - Command::NOTICE(ref t, ref m) => stringify("NOTICE", &[t], Some(m)), - Command::MOTD(Some(ref t)) => stringify("MOTD", &[], Some(t)), - Command::MOTD(None) => stringify("MOTD", &[], None), - Command::LUSERS(Some(ref m), Some(ref t)) => stringify("LUSERS", &[m], Some(t)), - Command::LUSERS(Some(ref m), None) => stringify("LUSERS", &[m], None), - Command::LUSERS(None, _) => stringify("LUSERS", &[], None), - Command::VERSION(Some(ref t)) => stringify("VERSION", &[], Some(t)), - Command::VERSION(None) => stringify("VERSION", &[], None), - Command::STATS(Some(ref q), Some(ref t)) => stringify("STATS", &[q], Some(t)), - Command::STATS(Some(ref q), None) => stringify("STATS", &[q], None), - Command::STATS(None, _) => stringify("STATS", &[], None), - Command::LINKS(Some(ref r), Some(ref s)) => stringify("LINKS", &[r], Some(s)), - Command::LINKS(None, Some(ref s)) => stringify("LINKS", &[], Some(s)), - Command::LINKS(_, None) => stringify("LINKS", &[], None), - Command::TIME(Some(ref t)) => stringify("TIME", &[], Some(t)), - Command::TIME(None) => stringify("TIME", &[], None), - Command::CONNECT(ref t, ref p, Some(ref r)) => stringify("CONNECT", &[t, p], Some(r)), - Command::CONNECT(ref t, ref p, None) => stringify("CONNECT", &[t, p], None), - Command::TRACE(Some(ref t)) => stringify("TRACE", &[], Some(t)), - Command::TRACE(None) => stringify("TRACE", &[], None), - Command::ADMIN(Some(ref t)) => stringify("ADMIN", &[], Some(t)), - Command::ADMIN(None) => stringify("ADMIN", &[], None), - Command::INFO(Some(ref t)) => stringify("INFO", &[], Some(t)), - Command::INFO(None) => stringify("INFO", &[], None), - Command::SERVLIST(Some(ref m), Some(ref t)) => stringify("SERVLIST", &[m], Some(t)), - Command::SERVLIST(Some(ref m), None) => stringify("SERVLIST", &[m], None), - Command::SERVLIST(None, _) => stringify("SERVLIST", &[], None), - Command::SQUERY(ref s, ref t) => stringify("SQUERY", &[s, t], None), - Command::WHO(Some(ref s), Some(true)) => stringify("WHO", &[s, "o"], None), - Command::WHO(Some(ref s), _) => stringify("WHO", &[s], None), - Command::WHO(None, _) => stringify("WHO", &[], None), - Command::WHOIS(Some(ref t), ref m) => stringify("WHOIS", &[t, m], None), - Command::WHOIS(None, ref m) => stringify("WHOIS", &[m], None), - Command::WHOWAS(ref n, Some(ref c), Some(ref t)) => { - stringify("WHOWAS", &[n, c], Some(t)) + Command::TOPIC(ref c, Some(ref t)) => stringify("TOPIC", &[c, t]), + Command::TOPIC(ref c, None) => stringify("TOPIC", &[c]), + Command::NAMES(Some(ref c), Some(ref t)) => stringify("NAMES", &[c, t]), + Command::NAMES(Some(ref c), None) => stringify("NAMES", &[c]), + Command::NAMES(None, _) => stringify("NAMES", &[]), + Command::LIST(Some(ref c), Some(ref t)) => stringify("LIST", &[c, t]), + Command::LIST(Some(ref c), None) => stringify("LIST", &[c]), + Command::LIST(None, _) => stringify("LIST", &[]), + Command::INVITE(ref n, ref c) => stringify("INVITE", &[n, c]), + Command::KICK(ref c, ref n, Some(ref r)) => stringify("KICK", &[c, n, r]), + Command::KICK(ref c, ref n, None) => stringify("KICK", &[c, n]), + Command::PRIVMSG(ref t, ref m) => stringify("PRIVMSG", &[t, m]), + Command::NOTICE(ref t, ref m) => stringify("NOTICE", &[t, m]), + Command::MOTD(Some(ref t)) => stringify("MOTD", &[t]), + Command::MOTD(None) => stringify("MOTD", &[]), + Command::LUSERS(Some(ref m), Some(ref t)) => stringify("LUSERS", &[m, t]), + Command::LUSERS(Some(ref m), None) => stringify("LUSERS", &[m]), + Command::LUSERS(None, _) => stringify("LUSERS", &[]), + Command::VERSION(Some(ref t)) => stringify("VERSION", &[t]), + Command::VERSION(None) => stringify("VERSION", &[]), + Command::STATS(Some(ref q), Some(ref t)) => stringify("STATS", &[q, t]), + Command::STATS(Some(ref q), None) => stringify("STATS", &[q]), + Command::STATS(None, _) => stringify("STATS", &[]), + Command::LINKS(Some(ref r), Some(ref s)) => stringify("LINKS", &[r, s]), + Command::LINKS(None, Some(ref s)) => stringify("LINKS", &[s]), + Command::LINKS(_, None) => stringify("LINKS", &[]), + Command::TIME(Some(ref t)) => stringify("TIME", &[t]), + Command::TIME(None) => stringify("TIME", &[]), + Command::CONNECT(ref t, ref p, Some(ref r)) => stringify("CONNECT", &[t, p, r]), + Command::CONNECT(ref t, ref p, None) => stringify("CONNECT", &[t, p]), + Command::TRACE(Some(ref t)) => stringify("TRACE", &[t]), + Command::TRACE(None) => stringify("TRACE", &[]), + Command::ADMIN(Some(ref t)) => stringify("ADMIN", &[t]), + Command::ADMIN(None) => stringify("ADMIN", &[]), + Command::INFO(Some(ref t)) => stringify("INFO", &[t]), + Command::INFO(None) => stringify("INFO", &[]), + Command::SERVLIST(Some(ref m), Some(ref t)) => stringify("SERVLIST", &[m, t]), + Command::SERVLIST(Some(ref m), None) => stringify("SERVLIST", &[m]), + Command::SERVLIST(None, _) => stringify("SERVLIST", &[]), + Command::SQUERY(ref s, ref t) => stringify("SQUERY", &[s, t]), + Command::WHO(Some(ref s), Some(true)) => stringify("WHO", &[s, "o"]), + Command::WHO(Some(ref s), _) => stringify("WHO", &[s]), + Command::WHO(None, _) => stringify("WHO", &[]), + Command::WHOIS(Some(ref t), ref m) => stringify("WHOIS", &[t, m]), + Command::WHOIS(None, ref m) => stringify("WHOIS", &[m]), + Command::WHOWAS(ref n, Some(ref c), Some(ref t)) => stringify("WHOWAS", &[n, c, t]), + Command::WHOWAS(ref n, Some(ref c), None) => stringify("WHOWAS", &[n, c]), + Command::WHOWAS(ref n, None, _) => stringify("WHOWAS", &[n]), + Command::KILL(ref n, ref c) => stringify("KILL", &[n, c]), + Command::PING(ref s, Some(ref t)) => stringify("PING", &[s, t]), + Command::PING(ref s, None) => stringify("PING", &[s]), + Command::PONG(ref s, Some(ref t)) => stringify("PONG", &[s, t]), + Command::PONG(ref s, None) => stringify("PONG", &[s]), + Command::ERROR(ref m) => stringify("ERROR", &[m]), + Command::AWAY(Some(ref m)) => stringify("AWAY", &[m]), + Command::AWAY(None) => stringify("AWAY", &[]), + Command::REHASH => stringify("REHASH", &[]), + Command::DIE => stringify("DIE", &[]), + Command::RESTART => stringify("RESTART", &[]), + Command::SUMMON(ref u, Some(ref t), Some(ref c)) => stringify("SUMMON", &[u, t, c]), + Command::SUMMON(ref u, Some(ref t), None) => stringify("SUMMON", &[u, t]), + Command::SUMMON(ref u, None, _) => stringify("SUMMON", &[u]), + Command::USERS(Some(ref t)) => stringify("USERS", &[t]), + Command::USERS(None) => stringify("USERS", &[]), + Command::WALLOPS(ref t) => stringify("WALLOPS", &[t]), + Command::USERHOST(ref u) => { + stringify("USERHOST", &u.iter().map(|s| &s[..]).collect::>()) } - Command::WHOWAS(ref n, Some(ref c), None) => stringify("WHOWAS", &[n, c], None), - Command::WHOWAS(ref n, None, _) => stringify("WHOWAS", &[n], None), - Command::KILL(ref n, ref c) => stringify("KILL", &[n], Some(c)), - Command::PING(ref s, Some(ref t)) => stringify("PING", &[s], Some(t)), - Command::PING(ref s, None) => stringify("PING", &[], Some(s)), - Command::PONG(ref s, Some(ref t)) => stringify("PONG", &[s], Some(t)), - Command::PONG(ref s, None) => stringify("PONG", &[], Some(s)), - Command::ERROR(ref m) => stringify("ERROR", &[], Some(m)), - Command::AWAY(Some(ref m)) => stringify("AWAY", &[], Some(m)), - Command::AWAY(None) => stringify("AWAY", &[], None), - Command::REHASH => stringify("REHASH", &[], None), - Command::DIE => stringify("DIE", &[], None), - Command::RESTART => stringify("RESTART", &[], None), - Command::SUMMON(ref u, Some(ref t), Some(ref c)) => { - stringify("SUMMON", &[u, t], Some(c)) - } - Command::SUMMON(ref u, Some(ref t), None) => stringify("SUMMON", &[u, t], None), - Command::SUMMON(ref u, None, _) => stringify("SUMMON", &[u], None), - Command::USERS(Some(ref t)) => stringify("USERS", &[], Some(t)), - Command::USERS(None) => stringify("USERS", &[], None), - Command::WALLOPS(ref t) => stringify("WALLOPS", &[], Some(t)), - Command::USERHOST(ref u) => stringify( - "USERHOST", - &u.iter().map(|s| &s[..]).collect::>(), - None, - ), Command::ISON(ref u) => { - stringify("ISON", &u.iter().map(|s| &s[..]).collect::>(), None) + stringify("ISON", &u.iter().map(|s| &s[..]).collect::>()) } - Command::SAJOIN(ref n, ref c) => stringify("SAJOIN", &[n, c], None), - Command::SAMODE(ref t, ref m, Some(ref p)) => stringify("SAMODE", &[t, m, p], None), - Command::SAMODE(ref t, ref m, None) => stringify("SAMODE", &[t, m], None), - Command::SANICK(ref o, ref n) => stringify("SANICK", &[o, n], None), - Command::SAPART(ref c, ref r) => stringify("SAPART", &[c], Some(r)), - Command::SAQUIT(ref c, ref r) => stringify("SAQUIT", &[c], Some(r)), + Command::SAJOIN(ref n, ref c) => stringify("SAJOIN", &[n, c]), + Command::SAMODE(ref t, ref m, Some(ref p)) => stringify("SAMODE", &[t, m, p]), + Command::SAMODE(ref t, ref m, None) => stringify("SAMODE", &[t, m]), + Command::SANICK(ref o, ref n) => stringify("SANICK", &[o, n]), + Command::SAPART(ref c, ref r) => stringify("SAPART", &[c, r]), + Command::SAQUIT(ref c, ref r) => stringify("SAQUIT", &[c, r]), - Command::NICKSERV(ref m) => stringify("NICKSERV", &[m], None), - Command::CHANSERV(ref m) => stringify("CHANSERV", &[m], None), - Command::OPERSERV(ref m) => stringify("OPERSERV", &[m], None), - Command::BOTSERV(ref m) => stringify("BOTSERV", &[m], None), - Command::HOSTSERV(ref m) => stringify("HOSTSERV", &[m], None), - Command::MEMOSERV(ref m) => stringify("MEMOSERV", &[m], None), - - Command::CAP(None, ref s, None, Some(ref p)) => { - stringify("CAP", &[s.to_str()], Some(p)) + Command::NICKSERV(ref p) => { + stringify("NICKSERV", &p.iter().map(|s| &s[..]).collect::>()) } - Command::CAP(None, ref s, None, None) => stringify("CAP", &[s.to_str()], None), + Command::CHANSERV(ref m) => stringify("CHANSERV", &[m]), + Command::OPERSERV(ref m) => stringify("OPERSERV", &[m]), + Command::BOTSERV(ref m) => stringify("BOTSERV", &[m]), + Command::HOSTSERV(ref m) => stringify("HOSTSERV", &[m]), + Command::MEMOSERV(ref m) => stringify("MEMOSERV", &[m]), + + Command::CAP(None, ref s, None, Some(ref p)) => stringify("CAP", &[s.to_str(), p]), + Command::CAP(None, ref s, None, None) => stringify("CAP", &[s.to_str()]), Command::CAP(Some(ref k), ref s, None, Some(ref p)) => { - stringify("CAP", &[k, s.to_str()], Some(p)) - } - Command::CAP(Some(ref k), ref s, None, None) => { - stringify("CAP", &[k, s.to_str()], None) + stringify("CAP", &[k, s.to_str(), p]) } + Command::CAP(Some(ref k), ref s, None, None) => stringify("CAP", &[k, s.to_str()]), Command::CAP(None, ref s, Some(ref c), Some(ref p)) => { - stringify("CAP", &[s.to_str(), c], Some(p)) - } - Command::CAP(None, ref s, Some(ref c), None) => { - stringify("CAP", &[s.to_str(), c], None) + stringify("CAP", &[s.to_str(), c, p]) } + Command::CAP(None, ref s, Some(ref c), None) => stringify("CAP", &[s.to_str(), c]), Command::CAP(Some(ref k), ref s, Some(ref c), Some(ref p)) => { - stringify("CAP", &[k, s.to_str(), c], Some(p)) + stringify("CAP", &[k, s.to_str(), c, p]) } Command::CAP(Some(ref k), ref s, Some(ref c), None) => { - stringify("CAP", &[k, s.to_str(), c], None) + stringify("CAP", &[k, s.to_str(), c]) } - Command::AUTHENTICATE(ref d) => stringify("AUTHENTICATE", &[d], None), - Command::ACCOUNT(ref a) => stringify("ACCOUNT", &[a], None), + Command::AUTHENTICATE(ref d) => stringify("AUTHENTICATE", &[d]), + Command::ACCOUNT(ref a) => stringify("ACCOUNT", &[a]), - Command::METADATA(ref t, Some(ref c), None, Some(ref p)) => { - stringify("METADATA", &[&t[..], c.to_str()], Some(p)) + Command::METADATA(ref t, Some(ref c), None) => { + stringify("METADATA", &[&t[..], c.to_str()]) } - Command::METADATA(ref t, Some(ref c), None, None) => { - stringify("METADATA", &[&t[..], c.to_str()], None) - } - - Command::METADATA(ref t, Some(ref c), Some(ref a), Some(ref p)) => stringify( + Command::METADATA(ref t, Some(ref c), Some(ref a)) => stringify( "METADATA", &vec![t, &c.to_str().to_owned()] .iter() .map(|s| &s[..]) .chain(a.iter().map(|s| &s[..])) .collect::>(), - Some(p), ), - Command::METADATA(ref t, Some(ref c), Some(ref a), None) => stringify( - "METADATA", - &vec![t, &c.to_str().to_owned()] - .iter() - .map(|s| &s[..]) - .chain(a.iter().map(|s| &s[..])) - .collect::>(), - None, - ), - Command::METADATA(ref t, None, None, Some(ref p)) => { - stringify("METADATA", &[t], Some(p)) - } - Command::METADATA(ref t, None, None, None) => stringify("METADATA", &[t], None), - Command::METADATA(ref t, None, Some(ref a), Some(ref p)) => stringify( - "METADATA", - &vec![t] - .iter() - .map(|s| &s[..]) - .chain(a.iter().map(|s| &s[..])) - .collect::>(), - Some(p), - ), - Command::METADATA(ref t, None, Some(ref a), None) => stringify( - "METADATA", - &vec![t] - .iter() - .map(|s| &s[..]) - .chain(a.iter().map(|s| &s[..])) - .collect::>(), - None, - ), - Command::MONITOR(ref c, Some(ref t)) => stringify("MONITOR", &[c, t], None), - Command::MONITOR(ref c, None) => stringify("MONITOR", &[c], None), + + // Note that it shouldn't be possible to have a later arg *and* be + // missing an early arg, so in order to serialize this as valid, we + // return it as just the command. + Command::METADATA(ref t, None, _) => stringify("METADATA", &[t]), + + Command::MONITOR(ref c, Some(ref t)) => stringify("MONITOR", &[c, t]), + Command::MONITOR(ref c, None) => stringify("MONITOR", &[c]), Command::BATCH(ref t, Some(ref c), Some(ref a)) => stringify( "BATCH", &vec![t, &c.to_str().to_owned()] @@ -429,9 +391,8 @@ impl<'a> From<&'a Command> for String { .map(|s| &s[..]) .chain(a.iter().map(|s| &s[..])) .collect::>(), - None, ), - Command::BATCH(ref t, Some(ref c), None) => stringify("BATCH", &[t, c.to_str()], None), + Command::BATCH(ref t, Some(ref c), None) => stringify("BATCH", &[t, c.to_str()]), Command::BATCH(ref t, None, Some(ref a)) => stringify( "BATCH", &vec![t] @@ -439,26 +400,16 @@ impl<'a> From<&'a Command> for String { .map(|s| &s[..]) .chain(a.iter().map(|s| &s[..])) .collect::>(), - None, ), - Command::BATCH(ref t, None, None) => stringify("BATCH", &[t], None), - Command::CHGHOST(ref u, ref h) => stringify("CHGHOST", &[u, h], None), + Command::BATCH(ref t, None, None) => stringify("BATCH", &[t]), + Command::CHGHOST(ref u, ref h) => stringify("CHGHOST", &[u, h]), - Command::Response(ref resp, ref a, Some(ref s)) => stringify( + Command::Response(ref resp, ref a) => stringify( &format!("{:03}", *resp as u16), &a.iter().map(|s| &s[..]).collect::>(), - Some(s), ), - Command::Response(ref resp, ref a, None) => stringify( - &format!("{:03}", *resp as u16), - &a.iter().map(|s| &s[..]).collect::>(), - None, - ), - Command::Raw(ref c, ref a, Some(ref s)) => { - stringify(c, &a.iter().map(|s| &s[..]).collect::>(), Some(s)) - } - Command::Raw(ref c, ref a, None) => { - stringify(c, &a.iter().map(|s| &s[..]).collect::>(), None) + Command::Raw(ref c, ref a) => { + stringify(c, &a.iter().map(|s| &s[..]).collect::>()) } } } @@ -466,1062 +417,500 @@ impl<'a> From<&'a Command> for String { impl Command { /// Constructs a new Command. - pub fn new( - cmd: &str, - args: Vec<&str>, - suffix: Option<&str>, - ) -> Result { + pub fn new(cmd: &str, args: Vec<&str>) -> Result { Ok(if cmd.eq_ignore_ascii_case("PASS") { - match suffix { - Some(suffix) => { - if !args.is_empty() { - raw(cmd, args, Some(suffix)) - } else { - Command::PASS(suffix.to_owned()) - } - } - None => { - if args.len() != 1 { - raw(cmd, args, suffix) - } else { - Command::PASS(args[0].to_owned()) - } - } + if args.len() != 1 { + raw(cmd, args) + } else { + Command::PASS(args[0].to_owned()) } } else if cmd.eq_ignore_ascii_case("NICK") { - match suffix { - Some(suffix) => { - if !args.is_empty() { - raw(cmd, args, Some(suffix)) - } else { - Command::NICK(suffix.to_owned()) - } - } - None => { - if args.len() != 1 { - raw(cmd, args, suffix) - } else { - Command::NICK(args[0].to_owned()) - } - } + if args.len() != 1 { + raw(cmd, args) + } else { + Command::NICK(args[0].to_owned()) } } else if cmd.eq_ignore_ascii_case("USER") { - match suffix { - Some(suffix) => { - if args.len() != 3 { - raw(cmd, args, Some(suffix)) - } else { - Command::USER(args[0].to_owned(), args[1].to_owned(), suffix.to_owned()) - } - } - None => { - if args.len() != 4 { - raw(cmd, args, suffix) - } else { - Command::USER(args[0].to_owned(), args[1].to_owned(), args[3].to_owned()) - } - } + if args.len() != 4 { + raw(cmd, args) + } else { + Command::USER(args[0].to_owned(), args[1].to_owned(), args[3].to_owned()) } } else if cmd.eq_ignore_ascii_case("OPER") { - match suffix { - Some(suffix) => { - if args.len() != 1 { - raw(cmd, args, Some(suffix)) - } else { - Command::OPER(args[0].to_owned(), suffix.to_owned()) - } - } - None => { - if args.len() != 2 { - raw(cmd, args, suffix) - } else { - Command::OPER(args[0].to_owned(), args[1].to_owned()) - } - } + if args.len() != 2 { + raw(cmd, args) + } else { + Command::OPER(args[0].to_owned(), args[1].to_owned()) } } else if cmd.eq_ignore_ascii_case("MODE") { - match suffix { - Some(suffix) => raw(cmd, args, Some(suffix)), - None => { - if args[0].is_channel_name() { - let arg = args[1..].join(" "); - Command::ChannelMODE(args[0].to_owned(), Mode::as_channel_modes(&arg)?) - } else { - let arg = args[1..].join(" "); - Command::UserMODE(args[0].to_owned(), Mode::as_user_modes(&arg)?) - } + if args.is_empty() { + raw(cmd, args) + } else { + if args[0].is_channel_name() { + Command::ChannelMODE(args[0].to_owned(), Mode::as_channel_modes(&args[1..])?) + } else { + Command::UserMODE(args[0].to_owned(), Mode::as_user_modes(&args[1..])?) } } } else if cmd.eq_ignore_ascii_case("SERVICE") { - match suffix { - Some(suffix) => { - if args.len() != 5 { - raw(cmd, args, Some(suffix)) - } else { - Command::SERVICE( - args[0].to_owned(), - args[1].to_owned(), - args[2].to_owned(), - args[3].to_owned(), - args[4].to_owned(), - suffix.to_owned(), - ) - } - } - None => { - if args.len() != 6 { - raw(cmd, args, suffix) - } else { - Command::SERVICE( - args[0].to_owned(), - args[1].to_owned(), - args[2].to_owned(), - args[3].to_owned(), - args[4].to_owned(), - args[5].to_owned(), - ) - } - } + if args.len() != 6 { + raw(cmd, args) + } else { + Command::SERVICE( + args[0].to_owned(), + args[1].to_owned(), + args[2].to_owned(), + args[3].to_owned(), + args[4].to_owned(), + args[5].to_owned(), + ) } } else if cmd.eq_ignore_ascii_case("QUIT") { - if !args.is_empty() { - raw(cmd, args, suffix) + if args.is_empty() { + Command::QUIT(None) + } else if args.len() == 1 { + Command::QUIT(Some(args[0].to_owned())) } else { - match suffix { - Some(suffix) => Command::QUIT(Some(suffix.to_owned())), - None => Command::QUIT(None), - } + raw(cmd, args) } } else if cmd.eq_ignore_ascii_case("SQUIT") { - match suffix { - Some(suffix) => { - if args.len() != 1 { - raw(cmd, args, Some(suffix)) - } else { - Command::SQUIT(args[0].to_owned(), suffix.to_owned()) - } - } - None => { - if args.len() != 2 { - raw(cmd, args, suffix) - } else { - Command::SQUIT(args[0].to_owned(), args[1].to_owned()) - } - } + if args.len() != 2 { + raw(cmd, args) + } else { + Command::SQUIT(args[0].to_owned(), args[1].to_owned()) } } else if cmd.eq_ignore_ascii_case("JOIN") { - match suffix { - Some(suffix) => { - if args.is_empty() { - Command::JOIN(suffix.to_owned(), None, None) - } else if args.len() == 1 { - Command::JOIN(args[0].to_owned(), Some(suffix.to_owned()), None) - } else if args.len() == 2 { - Command::JOIN( - args[0].to_owned(), - Some(args[1].to_owned()), - Some(suffix.to_owned()), - ) - } else { - raw(cmd, args, Some(suffix)) - } - } - None => { - if args.len() == 1 { - Command::JOIN(args[0].to_owned(), None, None) - } else if args.len() == 2 { - Command::JOIN(args[0].to_owned(), Some(args[1].to_owned()), None) - } else if args.len() == 3 { - Command::JOIN( - args[0].to_owned(), - Some(args[1].to_owned()), - Some(args[2].to_owned()), - ) - } else { - raw(cmd, args, suffix) - } - } + if args.len() == 1 { + Command::JOIN(args[0].to_owned(), None, None) + } else if args.len() == 2 { + Command::JOIN(args[0].to_owned(), Some(args[1].to_owned()), None) + } else if args.len() == 3 { + Command::JOIN( + args[0].to_owned(), + Some(args[1].to_owned()), + Some(args[2].to_owned()), + ) + } else { + raw(cmd, args) } } else if cmd.eq_ignore_ascii_case("PART") { - match suffix { - Some(suffix) => { - if args.is_empty() { - Command::PART(suffix.to_owned(), None) - } else if args.len() == 1 { - Command::PART(args[0].to_owned(), Some(suffix.to_owned())) - } else { - raw(cmd, args, Some(suffix)) - } - } - None => { - if args.len() == 1 { - Command::PART(args[0].to_owned(), None) - } else if args.len() == 2 { - Command::PART(args[0].to_owned(), Some(args[1].to_owned())) - } else { - raw(cmd, args, suffix) - } - } + if args.len() == 1 { + Command::PART(args[0].to_owned(), None) + } else if args.len() == 2 { + Command::PART(args[0].to_owned(), Some(args[1].to_owned())) + } else { + raw(cmd, args) } } else if cmd.eq_ignore_ascii_case("TOPIC") { - match suffix { - Some(suffix) => { - if args.is_empty() { - Command::TOPIC(suffix.to_owned(), None) - } else if args.len() == 1 { - Command::TOPIC(args[0].to_owned(), Some(suffix.to_owned())) - } else { - raw(cmd, args, Some(suffix)) - } - } - None => { - if args.len() == 1 { - Command::TOPIC(args[0].to_owned(), None) - } else if args.len() == 2 { - Command::TOPIC(args[0].to_owned(), Some(args[1].to_owned())) - } else { - raw(cmd, args, suffix) - } - } + if args.len() == 1 { + Command::TOPIC(args[0].to_owned(), None) + } else if args.len() == 2 { + Command::TOPIC(args[0].to_owned(), Some(args[1].to_owned())) + } else { + raw(cmd, args) } } else if cmd.eq_ignore_ascii_case("NAMES") { - match suffix { - Some(suffix) => { - if args.is_empty() { - Command::NAMES(Some(suffix.to_owned()), None) - } else if args.len() == 1 { - Command::NAMES(Some(args[0].to_owned()), Some(suffix.to_owned())) - } else { - raw(cmd, args, Some(suffix)) - } - } - None => { - if args.is_empty() { - Command::NAMES(None, None) - } else if args.len() == 1 { - Command::NAMES(Some(args[0].to_owned()), None) - } else if args.len() == 2 { - Command::NAMES(Some(args[0].to_owned()), Some(args[1].to_owned())) - } else { - raw(cmd, args, suffix) - } - } + if args.is_empty() { + Command::NAMES(None, None) + } else if args.len() == 1 { + Command::NAMES(Some(args[0].to_owned()), None) + } else if args.len() == 2 { + Command::NAMES(Some(args[0].to_owned()), Some(args[1].to_owned())) + } else { + raw(cmd, args) } } else if cmd.eq_ignore_ascii_case("LIST") { - match suffix { - Some(suffix) => { - if args.is_empty() { - Command::LIST(Some(suffix.to_owned()), None) - } else if args.len() == 1 { - Command::LIST(Some(args[0].to_owned()), Some(suffix.to_owned())) - } else { - raw(cmd, args, Some(suffix)) - } - } - None => { - if args.is_empty() { - Command::LIST(None, None) - } else if args.len() == 1 { - Command::LIST(Some(args[0].to_owned()), None) - } else if args.len() == 2 { - Command::LIST(Some(args[0].to_owned()), Some(args[1].to_owned())) - } else { - raw(cmd, args, suffix) - } - } + if args.is_empty() { + Command::LIST(None, None) + } else if args.len() == 1 { + Command::LIST(Some(args[0].to_owned()), None) + } else if args.len() == 2 { + Command::LIST(Some(args[0].to_owned()), Some(args[1].to_owned())) + } else { + raw(cmd, args) } } else if cmd.eq_ignore_ascii_case("INVITE") { - match suffix { - Some(suffix) => { - if args.len() != 1 { - raw(cmd, args, Some(suffix)) - } else { - Command::INVITE(args[0].to_owned(), suffix.to_owned()) - } - } - None => { - if args.len() != 2 { - raw(cmd, args, suffix) - } else { - Command::INVITE(args[0].to_owned(), args[1].to_owned()) - } - } + if args.len() != 2 { + raw(cmd, args) + } else { + Command::INVITE(args[0].to_owned(), args[1].to_owned()) } } else if cmd.eq_ignore_ascii_case("KICK") { - match suffix { - Some(suffix) => { - if args.len() != 2 { - raw(cmd, args, Some(suffix)) - } else { - Command::KICK( - args[0].to_owned(), - args[1].to_owned(), - Some(suffix.to_owned()), - ) - } - } - None => { - if args.len() != 2 { - raw(cmd, args, suffix) - } else { - Command::KICK(args[0].to_owned(), args[1].to_owned(), None) - } - } + if args.len() == 3 { + Command::KICK( + args[0].to_owned(), + args[1].to_owned(), + Some(args[2].to_owned()), + ) + } else if args.len() == 2 { + Command::KICK(args[0].to_owned(), args[1].to_owned(), None) + } else { + raw(cmd, args) } } else if cmd.eq_ignore_ascii_case("PRIVMSG") { - match suffix { - Some(suffix) => { - if args.len() != 1 { - raw(cmd, args, Some(suffix)) - } else { - Command::PRIVMSG(args[0].to_owned(), suffix.to_owned()) - } - } - None => raw(cmd, args, suffix), + if args.len() != 2 { + raw(cmd, args) + } else { + Command::PRIVMSG(args[0].to_owned(), args[1].to_owned()) } } else if cmd.eq_ignore_ascii_case("NOTICE") { - match suffix { - Some(suffix) => { - if args.len() != 1 { - raw(cmd, args, Some(suffix)) - } else { - Command::NOTICE(args[0].to_owned(), suffix.to_owned()) - } - } - None => raw(cmd, args, suffix), + if args.len() != 2 { + raw(cmd, args) + } else { + Command::NOTICE(args[0].to_owned(), args[1].to_owned()) } } else if cmd.eq_ignore_ascii_case("MOTD") { - if !args.is_empty() { - raw(cmd, args, suffix) + if args.is_empty() { + Command::MOTD(None) + } else if args.len() == 1 { + Command::MOTD(Some(args[0].to_owned())) } else { - match suffix { - Some(suffix) => Command::MOTD(Some(suffix.to_owned())), - None => Command::MOTD(None), - } + raw(cmd, args) } } else if cmd.eq_ignore_ascii_case("LUSERS") { - match suffix { - Some(suffix) => { - if args.is_empty() { - Command::LUSERS(Some(suffix.to_owned()), None) - } else if args.len() == 1 { - Command::LUSERS(Some(args[0].to_owned()), Some(suffix.to_owned())) - } else { - raw(cmd, args, Some(suffix)) - } - } - None => { - if args.is_empty() { - Command::LUSERS(None, None) - } else if args.len() == 1 { - Command::LUSERS(Some(args[0].to_owned()), None) - } else if args.len() == 2 { - Command::LUSERS(Some(args[0].to_owned()), Some(args[1].to_owned())) - } else { - raw(cmd, args, suffix) - } - } + if args.is_empty() { + Command::LUSERS(None, None) + } else if args.len() == 1 { + Command::LUSERS(Some(args[0].to_owned()), None) + } else if args.len() == 2 { + Command::LUSERS(Some(args[0].to_owned()), Some(args[1].to_owned())) + } else { + raw(cmd, args) } } else if cmd.eq_ignore_ascii_case("VERSION") { - if !args.is_empty() { - raw(cmd, args, suffix) + if args.is_empty() { + Command::VERSION(None) + } else if args.len() == 1 { + Command::VERSION(Some(args[0].to_owned())) } else { - match suffix { - Some(suffix) => Command::VERSION(Some(suffix.to_owned())), - None => Command::VERSION(None), - } + raw(cmd, args) } } else if cmd.eq_ignore_ascii_case("STATS") { - match suffix { - Some(suffix) => { - if args.is_empty() { - Command::STATS(Some(suffix.to_owned()), None) - } else if args.len() == 1 { - Command::STATS(Some(args[0].to_owned()), Some(suffix.to_owned())) - } else { - raw(cmd, args, Some(suffix)) - } - } - None => { - if args.is_empty() { - Command::STATS(None, None) - } else if args.len() == 1 { - Command::STATS(Some(args[0].to_owned()), None) - } else if args.len() == 2 { - Command::STATS(Some(args[0].to_owned()), Some(args[1].to_owned())) - } else { - raw(cmd, args, suffix) - } - } + if args.is_empty() { + Command::STATS(None, None) + } else if args.len() == 1 { + Command::STATS(Some(args[0].to_owned()), None) + } else if args.len() == 2 { + Command::STATS(Some(args[0].to_owned()), Some(args[1].to_owned())) + } else { + raw(cmd, args) } } else if cmd.eq_ignore_ascii_case("LINKS") { - match suffix { - Some(suffix) => { - if args.is_empty() { - Command::LINKS(None, Some(suffix.to_owned())) - } else if args.len() == 1 { - Command::LINKS(Some(args[0].to_owned()), Some(suffix.to_owned())) - } else { - raw(cmd, args, Some(suffix)) - } - } - None => { - if args.is_empty() { - Command::LINKS(None, None) - } else { - raw(cmd, args, suffix) - } - } + if args.is_empty() { + Command::LINKS(None, None) + } else if args.len() == 1 { + Command::LINKS(Some(args[0].to_owned()), None) + } else if args.len() == 2 { + Command::LINKS(Some(args[0].to_owned()), Some(args[1].to_owned())) + } else { + raw(cmd, args) } } else if cmd.eq_ignore_ascii_case("TIME") { - if !args.is_empty() { - raw(cmd, args, suffix) + if args.is_empty() { + Command::TIME(None) + } else if args.len() == 1 { + Command::TIME(Some(args[0].to_owned())) } else { - match suffix { - Some(suffix) => Command::TIME(Some(suffix.to_owned())), - None => Command::TIME(None), - } + raw(cmd, args) } } else if cmd.eq_ignore_ascii_case("CONNECT") { - match suffix { - Some(suffix) => { - if args.len() != 2 { - raw(cmd, args, Some(suffix)) - } else { - Command::CONNECT( - args[0].to_owned(), - args[1].to_owned(), - Some(suffix.to_owned()), - ) - } - } - None => { - if args.len() != 2 { - raw(cmd, args, suffix) - } else { - Command::CONNECT(args[0].to_owned(), args[1].to_owned(), None) - } - } + if args.len() != 2 { + raw(cmd, args) + } else { + Command::CONNECT(args[0].to_owned(), args[1].to_owned(), None) } } else if cmd.eq_ignore_ascii_case("TRACE") { - if !args.is_empty() { - raw(cmd, args, suffix) + if args.is_empty() { + Command::TRACE(None) + } else if args.len() == 1 { + Command::TRACE(Some(args[0].to_owned())) } else { - match suffix { - Some(suffix) => Command::TRACE(Some(suffix.to_owned())), - None => Command::TRACE(None), - } + raw(cmd, args) } } else if cmd.eq_ignore_ascii_case("ADMIN") { - if !args.is_empty() { - raw(cmd, args, suffix) + if args.is_empty() { + Command::ADMIN(None) + } else if args.len() == 1 { + Command::ADMIN(Some(args[0].to_owned())) } else { - match suffix { - Some(suffix) => Command::ADMIN(Some(suffix.to_owned())), - None => Command::ADMIN(None), - } + raw(cmd, args) } } else if cmd.eq_ignore_ascii_case("INFO") { - if !args.is_empty() { - raw(cmd, args, suffix) + if args.is_empty() { + Command::INFO(None) + } else if args.len() == 1 { + Command::INFO(Some(args[0].to_owned())) } else { - match suffix { - Some(suffix) => Command::INFO(Some(suffix.to_owned())), - None => Command::INFO(None), - } + raw(cmd, args) } } else if cmd.eq_ignore_ascii_case("SERVLIST") { - match suffix { - Some(suffix) => { - if args.is_empty() { - Command::SERVLIST(Some(suffix.to_owned()), None) - } else if args.len() == 1 { - Command::SERVLIST(Some(args[0].to_owned()), Some(suffix.to_owned())) - } else { - raw(cmd, args, Some(suffix)) - } - } - None => { - if args.is_empty() { - Command::SERVLIST(None, None) - } else if args.len() == 1 { - Command::SERVLIST(Some(args[0].to_owned()), None) - } else if args.len() == 2 { - Command::SERVLIST(Some(args[0].to_owned()), Some(args[1].to_owned())) - } else { - raw(cmd, args, suffix) - } - } + if args.is_empty() { + Command::SERVLIST(None, None) + } else if args.len() == 1 { + Command::SERVLIST(Some(args[0].to_owned()), None) + } else if args.len() == 2 { + Command::SERVLIST(Some(args[0].to_owned()), Some(args[1].to_owned())) + } else { + raw(cmd, args) } } else if cmd.eq_ignore_ascii_case("SQUERY") { - match suffix { - Some(suffix) => { - if args.len() != 1 { - raw(cmd, args, Some(suffix)) - } else { - Command::SQUERY(args[0].to_owned(), suffix.to_owned()) - } - } - None => { - if args.len() != 2 { - raw(cmd, args, suffix) - } else { - Command::SQUERY(args[0].to_owned(), args[1].to_owned()) - } - } + if args.len() != 2 { + raw(cmd, args) + } else { + Command::SQUERY(args[0].to_owned(), args[1].to_owned()) } } else if cmd.eq_ignore_ascii_case("WHO") { - match suffix { - Some(suffix) => { - if args.is_empty() { - Command::WHO(Some(suffix.to_owned()), None) - } else if args.len() == 1 { - Command::WHO(Some(args[0].to_owned()), Some(&suffix[..] == "o")) - } else { - raw(cmd, args, Some(suffix)) - } - } - None => { - if args.is_empty() { - Command::WHO(None, None) - } else if args.len() == 1 { - Command::WHO(Some(args[0].to_owned()), None) - } else if args.len() == 2 { - Command::WHO(Some(args[0].to_owned()), Some(&args[1][..] == "o")) - } else { - raw(cmd, args, suffix) - } - } + if args.is_empty() { + Command::WHO(None, None) + } else if args.len() == 1 { + Command::WHO(Some(args[0].to_owned()), None) + } else if args.len() == 2 { + Command::WHO(Some(args[0].to_owned()), Some(&args[1][..] == "o")) + } else { + raw(cmd, args) } } else if cmd.eq_ignore_ascii_case("WHOIS") { - match suffix { - Some(suffix) => { - if args.is_empty() { - Command::WHOIS(None, suffix.to_owned()) - } else if args.len() == 1 { - Command::WHOIS(Some(args[0].to_owned()), suffix.to_owned()) - } else { - raw(cmd, args, Some(suffix)) - } - } - None => { - if args.len() == 1 { - Command::WHOIS(None, args[0].to_owned()) - } else if args.len() == 2 { - Command::WHOIS(Some(args[0].to_owned()), args[1].to_owned()) - } else { - raw(cmd, args, suffix) - } - } + if args.len() == 1 { + Command::WHOIS(None, args[0].to_owned()) + } else if args.len() == 2 { + Command::WHOIS(Some(args[0].to_owned()), args[1].to_owned()) + } else { + raw(cmd, args) } } else if cmd.eq_ignore_ascii_case("WHOWAS") { - match suffix { - Some(suffix) => { - if args.is_empty() { - Command::WHOWAS(suffix.to_owned(), None, None) - } else if args.len() == 1 { - Command::WHOWAS(args[0].to_owned(), None, Some(suffix.to_owned())) - } else if args.len() == 2 { - Command::WHOWAS( - args[0].to_owned(), - Some(args[1].to_owned()), - Some(suffix.to_owned()), - ) - } else { - raw(cmd, args, Some(suffix)) - } - } - None => { - if args.len() == 1 { - Command::WHOWAS(args[0].to_owned(), None, None) - } else if args.len() == 2 { - Command::WHOWAS(args[0].to_owned(), None, Some(args[1].to_owned())) - } else if args.len() == 3 { - Command::WHOWAS( - args[0].to_owned(), - Some(args[1].to_owned()), - Some(args[2].to_owned()), - ) - } else { - raw(cmd, args, suffix) - } - } + if args.len() == 1 { + Command::WHOWAS(args[0].to_owned(), None, None) + } else if args.len() == 2 { + Command::WHOWAS(args[0].to_owned(), None, Some(args[1].to_owned())) + } else if args.len() == 3 { + Command::WHOWAS( + args[0].to_owned(), + Some(args[1].to_owned()), + Some(args[2].to_owned()), + ) + } else { + raw(cmd, args) } } else if cmd.eq_ignore_ascii_case("KILL") { - match suffix { - Some(suffix) => { - if args.len() != 1 { - raw(cmd, args, Some(suffix)) - } else { - Command::KILL(args[0].to_owned(), suffix.to_owned()) - } - } - None => { - if args.len() != 2 { - raw(cmd, args, suffix) - } else { - Command::KILL(args[0].to_owned(), args[1].to_owned()) - } - } + if args.len() != 2 { + raw(cmd, args) + } else { + Command::KILL(args[0].to_owned(), args[1].to_owned()) } } else if cmd.eq_ignore_ascii_case("PING") { - match suffix { - Some(suffix) => { - if args.is_empty() { - Command::PING(suffix.to_owned(), None) - } else if args.len() == 1 { - Command::PING(args[0].to_owned(), Some(suffix.to_owned())) - } else { - raw(cmd, args, Some(suffix)) - } - } - None => { - if args.len() == 1 { - Command::PING(args[0].to_owned(), None) - } else if args.len() == 2 { - Command::PING(args[0].to_owned(), Some(args[1].to_owned())) - } else { - raw(cmd, args, suffix) - } - } + if args.len() == 1 { + Command::PING(args[0].to_owned(), None) + } else if args.len() == 2 { + Command::PING(args[0].to_owned(), Some(args[1].to_owned())) + } else { + raw(cmd, args) } } else if cmd.eq_ignore_ascii_case("PONG") { - match suffix { - Some(suffix) => { - if args.is_empty() { - Command::PONG(suffix.to_owned(), None) - } else if args.len() == 1 { - Command::PONG(args[0].to_owned(), Some(suffix.to_owned())) - } else { - raw(cmd, args, Some(suffix)) - } - } - None => { - if args.len() == 1 { - Command::PONG(args[0].to_owned(), None) - } else if args.len() == 2 { - Command::PONG(args[0].to_owned(), Some(args[1].to_owned())) - } else { - raw(cmd, args, suffix) - } - } + if args.len() == 1 { + Command::PONG(args[0].to_owned(), None) + } else if args.len() == 2 { + Command::PONG(args[0].to_owned(), Some(args[1].to_owned())) + } else { + raw(cmd, args) } } else if cmd.eq_ignore_ascii_case("ERROR") { - match suffix { - Some(suffix) => { - if args.is_empty() { - Command::ERROR(suffix.to_owned()) - } else { - raw(cmd, args, Some(suffix)) - } - } - None => raw(cmd, args, suffix), + if args.len() != 1 { + raw(cmd, args) + } else { + Command::ERROR(args[0].to_owned()) } } else if cmd.eq_ignore_ascii_case("AWAY") { - match suffix { - Some(suffix) => { - if args.is_empty() { - Command::AWAY(Some(suffix.to_owned())) - } else { - raw(cmd, args, Some(suffix)) - } - } - None => raw(cmd, args, suffix), + if args.is_empty() { + Command::AWAY(None) + } else if args.len() == 1 { + Command::AWAY(Some(args[0].to_owned())) + } else { + raw(cmd, args) } } else if cmd.eq_ignore_ascii_case("REHASH") { if args.is_empty() { Command::REHASH } else { - raw(cmd, args, suffix) + raw(cmd, args) } } else if cmd.eq_ignore_ascii_case("DIE") { if args.is_empty() { Command::DIE } else { - raw(cmd, args, suffix) + raw(cmd, args) } } else if cmd.eq_ignore_ascii_case("RESTART") { if args.is_empty() { Command::RESTART } else { - raw(cmd, args, suffix) + raw(cmd, args) } } else if cmd.eq_ignore_ascii_case("SUMMON") { - match suffix { - Some(suffix) => { - if args.is_empty() { - Command::SUMMON(suffix.to_owned(), None, None) - } else if args.len() == 1 { - Command::SUMMON(args[0].to_owned(), Some(suffix.to_owned()), None) - } else if args.len() == 2 { - Command::SUMMON( - args[0].to_owned(), - Some(args[1].to_owned()), - Some(suffix.to_owned()), - ) - } else { - raw(cmd, args, Some(suffix)) - } - } - None => { - if args.len() == 1 { - Command::SUMMON(args[0].to_owned(), None, None) - } else if args.len() == 2 { - Command::SUMMON(args[0].to_owned(), Some(args[1].to_owned()), None) - } else if args.len() == 3 { - Command::SUMMON( - args[0].to_owned(), - Some(args[1].to_owned()), - Some(args[2].to_owned()), - ) - } else { - raw(cmd, args, suffix) - } - } + if args.len() == 1 { + Command::SUMMON(args[0].to_owned(), None, None) + } else if args.len() == 2 { + Command::SUMMON(args[0].to_owned(), Some(args[1].to_owned()), None) + } else if args.len() == 3 { + Command::SUMMON( + args[0].to_owned(), + Some(args[1].to_owned()), + Some(args[2].to_owned()), + ) + } else { + raw(cmd, args) } } else if cmd.eq_ignore_ascii_case("USERS") { - match suffix { - Some(suffix) => { - if !args.is_empty() { - raw(cmd, args, Some(suffix)) - } else { - Command::USERS(Some(suffix.to_owned())) - } - } - None => { - if args.len() != 1 { - raw(cmd, args, suffix) - } else { - Command::USERS(Some(args[0].to_owned())) - } - } + if args.len() != 1 { + raw(cmd, args) + } else { + Command::USERS(Some(args[0].to_owned())) } } else if cmd.eq_ignore_ascii_case("WALLOPS") { - match suffix { - Some(suffix) => { - if !args.is_empty() { - raw(cmd, args, Some(suffix)) - } else { - Command::WALLOPS(suffix.to_owned()) - } - } - None => { - if args.len() != 1 { - raw(cmd, args, suffix) - } else { - Command::WALLOPS(args[0].to_owned()) - } - } + if args.len() != 1 { + raw(cmd, args) + } else { + Command::WALLOPS(args[0].to_owned()) } } else if cmd.eq_ignore_ascii_case("USERHOST") { - if suffix.is_none() { - Command::USERHOST(args.into_iter().map(|s| s.to_owned()).collect()) - } else { - raw(cmd, args, suffix) - } + Command::USERHOST(args.into_iter().map(|s| s.to_owned()).collect()) } else if cmd.eq_ignore_ascii_case("ISON") { - if suffix.is_none() { - Command::USERHOST(args.into_iter().map(|s| s.to_owned()).collect()) - } else { - raw(cmd, args, suffix) - } + Command::USERHOST(args.into_iter().map(|s| s.to_owned()).collect()) } else if cmd.eq_ignore_ascii_case("SAJOIN") { - match suffix { - Some(suffix) => { - if args.len() != 1 { - raw(cmd, args, Some(suffix)) - } else { - Command::SAJOIN(args[0].to_owned(), suffix.to_owned()) - } - } - None => { - if args.len() != 2 { - raw(cmd, args, suffix) - } else { - Command::SAJOIN(args[0].to_owned(), args[1].to_owned()) - } - } + if args.len() != 2 { + raw(cmd, args) + } else { + Command::SAJOIN(args[0].to_owned(), args[1].to_owned()) } } else if cmd.eq_ignore_ascii_case("SAMODE") { - match suffix { - Some(suffix) => { - if args.len() == 1 { - Command::SAMODE(args[0].to_owned(), suffix.to_owned(), None) - } else if args.len() == 2 { - Command::SAMODE( - args[0].to_owned(), - args[1].to_owned(), - Some(suffix.to_owned()), - ) - } else { - raw(cmd, args, Some(suffix)) - } - } - None => { - if args.len() == 2 { - Command::SAMODE(args[0].to_owned(), args[1].to_owned(), None) - } else if args.len() == 3 { - Command::SAMODE( - args[0].to_owned(), - args[1].to_owned(), - Some(args[2].to_owned()), - ) - } else { - raw(cmd, args, suffix) - } - } + if args.len() == 2 { + Command::SAMODE(args[0].to_owned(), args[1].to_owned(), None) + } else if args.len() == 3 { + Command::SAMODE( + args[0].to_owned(), + args[1].to_owned(), + Some(args[2].to_owned()), + ) + } else { + raw(cmd, args) } } else if cmd.eq_ignore_ascii_case("SANICK") { - match suffix { - Some(suffix) => { - if args.len() != 1 { - raw(cmd, args, Some(suffix)) - } else { - Command::SANICK(args[0].to_owned(), suffix.to_owned()) - } - } - None => { - if args.len() != 2 { - raw(cmd, args, suffix) - } else { - Command::SANICK(args[0].to_owned(), args[1].to_owned()) - } - } + if args.len() != 2 { + raw(cmd, args) + } else { + Command::SANICK(args[0].to_owned(), args[1].to_owned()) } } else if cmd.eq_ignore_ascii_case("SAPART") { - match suffix { - Some(suffix) => { - if args.len() != 1 { - raw(cmd, args, Some(suffix)) - } else { - Command::SAPART(args[0].to_owned(), suffix.to_owned()) - } - } - None => { - if args.len() != 2 { - raw(cmd, args, suffix) - } else { - Command::SAPART(args[0].to_owned(), args[1].to_owned()) - } - } + if args.len() != 2 { + raw(cmd, args) + } else { + Command::SAPART(args[0].to_owned(), args[1].to_owned()) } } else if cmd.eq_ignore_ascii_case("SAQUIT") { - match suffix { - Some(suffix) => { - if args.len() != 1 { - raw(cmd, args, Some(suffix)) - } else { - Command::SAQUIT(args[0].to_owned(), suffix.to_owned()) - } - } - None => { - if args.len() != 2 { - raw(cmd, args, suffix) - } else { - Command::SAQUIT(args[0].to_owned(), args[1].to_owned()) - } - } + if args.len() != 2 { + raw(cmd, args) + } else { + Command::SAQUIT(args[0].to_owned(), args[1].to_owned()) } } else if cmd.eq_ignore_ascii_case("NICKSERV") { - match suffix { - Some(suffix) => { - if !args.is_empty() { - raw(cmd, args, Some(suffix)) - } else { - Command::NICKSERV(suffix.to_owned()) - } - } - None => { - if args.len() != 1 { - raw(cmd, args, suffix) - } else { - Command::NICKSERV(args[0].to_owned()) - } - } + if args.len() != 1 { + raw(cmd, args) + } else { + Command::NICKSERV(args[1..].iter().map(|s| s.to_string()).collect()) } } else if cmd.eq_ignore_ascii_case("CHANSERV") { - match suffix { - Some(suffix) => { - if !args.is_empty() { - raw(cmd, args, Some(suffix)) - } else { - Command::CHANSERV(suffix.to_owned()) - } - } - None => { - if args.len() != 1 { - raw(cmd, args, suffix) - } else { - Command::CHANSERV(args[0].to_owned()) - } - } + if args.len() != 1 { + raw(cmd, args) + } else { + Command::CHANSERV(args[0].to_owned()) } } else if cmd.eq_ignore_ascii_case("OPERSERV") { - match suffix { - Some(suffix) => { - if !args.is_empty() { - raw(cmd, args, Some(suffix)) - } else { - Command::OPERSERV(suffix.to_owned()) - } - } - None => { - if args.len() != 1 { - raw(cmd, args, suffix) - } else { - Command::OPERSERV(args[0].to_owned()) - } - } + if args.len() != 1 { + raw(cmd, args) + } else { + Command::OPERSERV(args[0].to_owned()) } } else if cmd.eq_ignore_ascii_case("BOTSERV") { - match suffix { - Some(suffix) => { - if !args.is_empty() { - raw(cmd, args, Some(suffix)) - } else { - Command::BOTSERV(suffix.to_owned()) - } - } - None => { - if args.len() != 1 { - raw(cmd, args, suffix) - } else { - Command::BOTSERV(args[0].to_owned()) - } - } + if args.len() != 1 { + raw(cmd, args) + } else { + Command::BOTSERV(args[0].to_owned()) } } else if cmd.eq_ignore_ascii_case("HOSTSERV") { - match suffix { - Some(suffix) => { - if !args.is_empty() { - raw(cmd, args, Some(suffix)) - } else { - Command::HOSTSERV(suffix.to_owned()) - } - } - None => { - if args.len() != 1 { - raw(cmd, args, suffix) - } else { - Command::HOSTSERV(args[0].to_owned()) - } - } + if args.len() != 1 { + raw(cmd, args) + } else { + Command::HOSTSERV(args[0].to_owned()) } } else if cmd.eq_ignore_ascii_case("MEMOSERV") { - match suffix { - Some(suffix) => { - if !args.is_empty() { - raw(cmd, args, Some(suffix)) - } else { - Command::MEMOSERV(suffix.to_owned()) - } - } - None => { - if args.len() != 1 { - raw(cmd, args, suffix) - } else { - Command::MEMOSERV(args[0].to_owned()) - } - } + if args.len() != 1 { + raw(cmd, args) + } else { + Command::MEMOSERV(args[0].to_owned()) } } else if cmd.eq_ignore_ascii_case("CAP") { if args.len() == 1 { if let Ok(cmd) = args[0].parse() { - match suffix { - Some(suffix) => Command::CAP(None, cmd, None, Some(suffix.to_owned())), - None => Command::CAP(None, cmd, None, None), - } + Command::CAP(None, cmd, None, None) } else { - raw(cmd, args, suffix) + raw(cmd, args) } } else if args.len() == 2 { if let Ok(cmd) = args[0].parse() { - match suffix { - Some(suffix) => Command::CAP( - None, - cmd, - Some(args[1].to_owned()), - Some(suffix.to_owned()), - ), - None => Command::CAP(None, cmd, Some(args[1].to_owned()), None), - } + Command::CAP(None, cmd, Some(args[1].to_owned()), None) } else if let Ok(cmd) = args[1].parse() { - match suffix { - Some(suffix) => Command::CAP( - Some(args[0].to_owned()), - cmd, - None, - Some(suffix.to_owned()), - ), - None => Command::CAP(Some(args[0].to_owned()), cmd, None, None), - } + Command::CAP(Some(args[0].to_owned()), cmd, None, None) } else { - raw(cmd, args, suffix) + raw(cmd, args) } } else if args.len() == 3 { - if let Ok(cmd) = args[1].parse() { - match suffix { - Some(suffix) => Command::CAP( - Some(args[0].to_owned()), - cmd, - Some(args[2].to_owned()), - Some(suffix.to_owned()), - ), - None => Command::CAP( - Some(args[0].to_owned()), - cmd, - Some(args[2].to_owned()), - None, - ), - } + if let Ok(cmd) = args[0].parse() { + Command::CAP( + None, + cmd, + Some(args[1].to_owned()), + Some(args[2].to_owned()), + ) + } else if let Ok(cmd) = args[1].parse() { + Command::CAP( + Some(args[0].to_owned()), + cmd, + Some(args[2].to_owned()), + None, + ) } else { - raw(cmd, args, suffix) + raw(cmd, args) + } + } else if args.len() == 4 { + if let Ok(cmd) = args[1].parse() { + Command::CAP( + Some(args[0].to_owned()), + cmd, + Some(args[2].to_owned()), + Some(args[3].to_owned()), + ) + } else { + raw(cmd, args) } } else { - raw(cmd, args, suffix) + raw(cmd, args) } } else if cmd.eq_ignore_ascii_case("AUTHENTICATE") { - match suffix { - Some(suffix) => { - if args.is_empty() { - Command::AUTHENTICATE(suffix.to_owned()) - } else { - raw(cmd, args, Some(suffix)) - } - } - None => { - if args.len() == 1 { - Command::AUTHENTICATE(args[0].to_owned()) - } else { - raw(cmd, args, suffix) - } - } + if args.len() == 1 { + Command::AUTHENTICATE(args[0].to_owned()) + } else { + raw(cmd, args) } } else if cmd.eq_ignore_ascii_case("ACCOUNT") { - match suffix { - Some(suffix) => { - if args.is_empty() { - Command::ACCOUNT(suffix.to_owned()) - } else { - raw(cmd, args, Some(suffix)) - } - } - None => { - if args.len() == 1 { - Command::ACCOUNT(args[0].to_owned()) - } else { - raw(cmd, args, suffix) - } - } + if args.len() == 1 { + Command::ACCOUNT(args[0].to_owned()) + } else { + raw(cmd, args) } } else if cmd.eq_ignore_ascii_case("METADATA") { if args.len() == 2 { - match suffix { - Some(_) => raw(cmd, args, suffix), - None => match args[1].parse() { - Ok(c) => Command::METADATA(args[0].to_owned(), Some(c), None, None), - Err(_) => raw(cmd, args, suffix), - }, + match args[1].parse() { + Ok(c) => Command::METADATA(args[0].to_owned(), Some(c), None), + Err(_) => raw(cmd, args), } } else if args.len() > 2 { match args[1].parse() { @@ -1529,103 +918,63 @@ impl Command { args[0].to_owned(), Some(c), Some(args.into_iter().skip(1).map(|s| s.to_owned()).collect()), - suffix.map(|s| s.to_owned()), ), Err(_) => { - if args.len() == 3 && suffix.is_some() { + if args.len() == 3 { Command::METADATA( args[0].to_owned(), None, Some(args.into_iter().skip(1).map(|s| s.to_owned()).collect()), - suffix.map(|s| s.to_owned()), ) } else { - raw(cmd, args, suffix) + raw(cmd, args) } } } } else { - raw(cmd, args, suffix) + raw(cmd, args) } } else if cmd.eq_ignore_ascii_case("MONITOR") { - if args.len() == 1 { - Command::MONITOR(args[0].to_owned(), suffix.map(|s| s.to_owned())) + if args.len() == 2 { + Command::MONITOR(args[0].to_owned(), Some(args[1].to_owned())) + } else if args.len() == 1 { + Command::MONITOR(args[0].to_owned(), None) } else { - raw(cmd, args, suffix) + raw(cmd, args) } } else if cmd.eq_ignore_ascii_case("BATCH") { - match suffix { - Some(suffix) => { - if args.is_empty() { - Command::BATCH(suffix.to_owned(), None, None) - } else if args.len() == 1 { - Command::BATCH(args[0].to_owned(), Some(suffix.parse().unwrap()), None) - } else if args.len() > 1 { - Command::BATCH( - args[0].to_owned(), - Some(args[1].parse().unwrap()), - Some( - vec![suffix.to_owned()] - .into_iter() - .chain(args.into_iter().skip(2).map(|s| s.to_owned())) - .collect(), - ), - ) - } else { - raw(cmd, args, Some(suffix)) - } - } - None => { - if args.len() == 1 { - Command::BATCH(args[0].to_owned(), None, None) - } else if args.len() == 2 { - Command::BATCH(args[0].to_owned(), Some(args[1].parse().unwrap()), None) - } else if args.len() > 2 { - Command::BATCH( - args[0].to_owned(), - Some(args[1].parse().unwrap()), - Some(args.iter().skip(2).map(|&s| s.to_owned()).collect()), - ) - } else { - raw(cmd, args, suffix) - } - } + if args.len() == 1 { + Command::BATCH(args[0].to_owned(), None, None) + } else if args.len() == 2 { + Command::BATCH(args[0].to_owned(), Some(args[1].parse().unwrap()), None) + } else if args.len() > 2 { + Command::BATCH( + args[0].to_owned(), + Some(args[1].parse().unwrap()), + Some(args.iter().skip(2).map(|&s| s.to_owned()).collect()), + ) + } else { + raw(cmd, args) } } else if cmd.eq_ignore_ascii_case("CHGHOST") { - match suffix { - Some(suffix) => { - if args.len() == 1 { - Command::CHGHOST(args[0].to_owned(), suffix.to_owned()) - } else { - raw(cmd, args, Some(suffix)) - } - } - None => { - if args.len() == 2 { - Command::CHGHOST(args[0].to_owned(), args[1].to_owned()) - } else { - raw(cmd, args, suffix) - } - } + if args.len() == 2 { + Command::CHGHOST(args[0].to_owned(), args[1].to_owned()) + } else { + raw(cmd, args) } } else if let Ok(resp) = cmd.parse() { - Command::Response( - resp, - args.into_iter().map(|s| s.to_owned()).collect(), - suffix.map(|s| s.to_owned()), - ) + Command::Response(resp, args.into_iter().map(|s| s.to_owned()).collect()) } else { - raw(cmd, args, suffix) + raw(cmd, args) }) } } /// Makes a raw message from the specified command, arguments, and suffix. -fn raw(cmd: &str, args: Vec<&str>, suffix: Option<&str>) -> Command { +fn raw(cmd: &str, args: Vec<&str>) -> Command { Command::Raw( cmd.to_owned(), args.into_iter().map(|s| s.to_owned()).collect(), - suffix.map(|s| s.to_owned()), ) } @@ -1790,7 +1139,6 @@ mod test { String::from(&Command::Response( Response::RPL_WELCOME, vec!["foo".into()], - None )) == "001 foo" ); } diff --git a/irc-proto/src/message.rs b/irc-proto/src/message.rs index 8fbb544..e135689 100644 --- a/irc-proto/src/message.rs +++ b/irc-proto/src/message.rs @@ -36,7 +36,7 @@ impl Message { /// # use irc_proto::Message; /// # fn main() { /// let message = Message::new( - /// Some("nickname!username@hostname"), "JOIN", vec!["#channel"], None + /// Some("nickname!username@hostname"), "JOIN", vec!["#channel"] /// ).unwrap(); /// # } /// ``` @@ -44,9 +44,8 @@ impl Message { prefix: Option<&str>, command: &str, args: Vec<&str>, - suffix: Option<&str>, ) -> Result { - Message::with_tags(None, prefix, command, args, suffix) + Message::with_tags(None, prefix, command, args) } /// Creates a new IRCv3.2 message from the given components, including message tags. These tags @@ -57,12 +56,11 @@ impl Message { prefix: Option<&str>, command: &str, args: Vec<&str>, - suffix: Option<&str>, ) -> Result { Ok(Message { tags: tags, prefix: prefix.map(|p| p.into()), - command: Command::new(command, args, suffix)?, + command: Command::new(command, args)?, }) } @@ -74,7 +72,7 @@ impl Message { /// # use irc_proto::Message; /// # fn main() { /// let message = Message::new( - /// Some("nickname!username@hostname"), "JOIN", vec!["#channel"], None + /// Some("nickname!username@hostname"), "JOIN", vec!["#channel"] /// ).unwrap(); /// assert_eq!(message.source_nickname(), Some("nickname")); /// # } @@ -98,11 +96,11 @@ impl Message { /// # use irc_proto::Message; /// # fn main() { /// let msg1 = Message::new( - /// Some("ada"), "PRIVMSG", vec!["#channel"], Some("Hi, everyone!") + /// Some("ada"), "PRIVMSG", vec!["#channel", "Hi, everyone!"] /// ).unwrap(); /// assert_eq!(msg1.response_target(), Some("#channel")); /// let msg2 = Message::new( - /// Some("ada"), "PRIVMSG", vec!["betsy"], Some("betsy: hi") + /// Some("ada"), "PRIVMSG", vec!["betsy", "betsy: hi"] /// ).unwrap(); /// assert_eq!(msg2.response_target(), Some("ada")); /// # } @@ -123,7 +121,7 @@ impl Message { /// # use irc_proto::Message; /// # fn main() { /// let msg = Message::new( - /// Some("ada"), "PRIVMSG", vec!["#channel"], Some("Hi, everyone!") + /// Some("ada"), "PRIVMSG", vec!["#channel", "Hi, everyone!"] /// ).unwrap(); /// assert_eq!(msg.to_string(), ":ada PRIVMSG #channel :Hi, everyone!\r\n"); /// # } @@ -243,9 +241,12 @@ impl FromStr for Message { } }; - let args: Vec<_> = state.splitn(14, ' ').filter(|s| !s.is_empty()).collect(); + let mut args: Vec<_> = state.splitn(14, ' ').filter(|s| !s.is_empty()).collect(); + if let Some(suffix) = suffix { + args.push(suffix); + } - Message::with_tags(tags, prefix, command, args, suffix).map_err(|e| { + Message::with_tags(tags, prefix, command, args).map_err(|e| { ProtocolError::InvalidMessage { string: s.to_owned(), cause: e, @@ -286,7 +287,7 @@ mod test { command: PRIVMSG(format!("test"), format!("Testing!")), }; assert_eq!( - Message::new(None, "PRIVMSG", vec!["test"], Some("Testing!")).unwrap(), + Message::new(None, "PRIVMSG", vec!["test", "Testing!"]).unwrap(), message ) } @@ -294,56 +295,56 @@ mod test { #[test] fn source_nickname() { assert_eq!( - Message::new(None, "PING", vec![], Some("data")) + Message::new(None, "PING", vec!["data"]) .unwrap() .source_nickname(), None ); assert_eq!( - Message::new(Some("irc.test.net"), "PING", vec![], Some("data")) + Message::new(Some("irc.test.net"), "PING", vec!["data"]) .unwrap() .source_nickname(), None ); assert_eq!( - Message::new(Some("test!test@test"), "PING", vec![], Some("data")) + Message::new(Some("test!test@test"), "PING", vec!["data"]) .unwrap() .source_nickname(), Some("test") ); assert_eq!( - Message::new(Some("test@test"), "PING", vec![], Some("data")) + Message::new(Some("test@test"), "PING", vec!["data"]) .unwrap() .source_nickname(), Some("test") ); assert_eq!( - Message::new(Some("test!test@irc.test.com"), "PING", vec![], Some("data")) + Message::new(Some("test!test@irc.test.com"), "PING", vec!["data"]) .unwrap() .source_nickname(), Some("test") ); assert_eq!( - Message::new(Some("test!test@127.0.0.1"), "PING", vec![], Some("data")) + Message::new(Some("test!test@127.0.0.1"), "PING", vec!["data"]) .unwrap() .source_nickname(), Some("test") ); assert_eq!( - Message::new(Some("test@test.com"), "PING", vec![], Some("data")) + Message::new(Some("test@test.com"), "PING", vec!["data"]) .unwrap() .source_nickname(), Some("test") ); assert_eq!( - Message::new(Some("test"), "PING", vec![], Some("data")) + Message::new(Some("test"), "PING", vec!["data"]) .unwrap() .source_nickname(), Some("test") @@ -357,7 +358,7 @@ mod test { prefix: None, command: PRIVMSG(format!("test"), format!("Testing!")), }; - assert_eq!(&message.to_string()[..], "PRIVMSG test :Testing!\r\n"); + assert_eq!(&message.to_string()[..], "PRIVMSG test Testing!\r\n"); let message = Message { tags: None, prefix: Some("test!test@test".into()), @@ -465,8 +466,7 @@ mod test { prefix: Some("test!test@test".into()), command: Raw( format!("COMMAND"), - vec![format!("ARG:test")], - Some(format!("Testing!")), + vec![format!("ARG:test"), format!("Testing!")], ), }; let msg: Message = ":test!test@test COMMAND ARG:test :Testing!\r\n".into(); diff --git a/irc-proto/src/mode.rs b/irc-proto/src/mode.rs index 03a0cf5..a22d5ce 100644 --- a/irc-proto/src/mode.rs +++ b/irc-proto/src/mode.rs @@ -13,6 +13,9 @@ pub trait ModeType: fmt::Display + fmt::Debug + Clone + PartialEq { /// Returns true if this mode takes an argument, and false otherwise. fn takes_arg(&self) -> bool; + + /// Creates a Mode from a given char. + fn from_char(c: char) -> Self; } /// User modes for the MODE command. @@ -47,9 +50,7 @@ impl ModeType for UserMode { fn takes_arg(&self) -> bool { false } -} -impl UserMode { fn from_char(c: char) -> UserMode { use self::UserMode::*; @@ -144,9 +145,7 @@ impl ModeType for ChannelMode { _ => false, } } -} -impl ChannelMode { fn from_char(c: char) -> ChannelMode { use self::ChannelMode::*; @@ -252,49 +251,8 @@ enum PlusMinus { impl Mode { // TODO: turning more edge cases into errors. /// Parses the specified mode string as user modes. - pub fn as_user_modes(s: &str) -> Result>, MessageParseError> { - use self::PlusMinus::*; - - let mut res = vec![]; - let mut pieces = s.split(' '); - for term in pieces.clone() { - if term.starts_with('+') || term.starts_with('-') { - let _ = pieces.next(); - - let mut chars = term.chars(); - let init = match chars.next() { - Some('+') => Plus, - Some('-') => Minus, - Some(c) => { - return Err(InvalidModeString { - string: s.to_owned(), - cause: InvalidModeModifier { modifier: c }, - }) - } - None => { - return Err(InvalidModeString { - string: s.to_owned(), - cause: MissingModeModifier, - }) - } - }; - - for c in chars { - let mode = UserMode::from_char(c); - let arg = if mode.takes_arg() { - pieces.next() - } else { - None - }; - res.push(match init { - Plus => Mode::Plus(mode, arg.map(|s| s.to_owned())), - Minus => Mode::Minus(mode, arg.map(|s| s.to_owned())), - }) - } - } - } - - Ok(res) + pub fn as_user_modes(pieces: &[&str]) -> Result>, MessageParseError> { + parse_modes(pieces) } } @@ -302,48 +260,67 @@ impl Mode { impl Mode { // TODO: turning more edge cases into errors. /// Parses the specified mode string as channel modes. - pub fn as_channel_modes(s: &str) -> Result>, MessageParseError> { - use self::PlusMinus::*; + pub fn as_channel_modes(pieces: &[&str]) -> Result>, MessageParseError> { + parse_modes(pieces) + } +} - let mut res = vec![]; - let mut pieces = s.split(' '); - for term in pieces.clone() { - if term.starts_with('+') || term.starts_with('-') { - let _ = pieces.next(); +fn parse_modes(pieces: &[&str]) -> Result>, MessageParseError> +where + T: ModeType, +{ + use self::PlusMinus::*; - let mut chars = term.chars(); - let init = match chars.next() { - Some('+') => Plus, - Some('-') => Minus, - Some(c) => { - return Err(InvalidModeString { - string: s.to_owned(), - cause: InvalidModeModifier { modifier: c }, - }) - } - None => { - return Err(InvalidModeString { - string: s.to_owned(), - cause: MissingModeModifier, - }) - } - }; + let mut res = vec![]; - for c in chars { - let mode = ChannelMode::from_char(c); + if let Some((first, rest)) = pieces.split_first() { + let mut modes = first.chars(); + let mut args = rest.iter(); + + let mut cur_mod = match modes.next() { + Some('+') => Plus, + Some('-') => Minus, + Some(c) => { + return Err(InvalidModeString { + string: pieces.join(" ").to_owned(), + cause: InvalidModeModifier { modifier: c }, + }) + } + None => { + return Err(InvalidModeString { + string: pieces.join(" ").to_owned(), + cause: MissingModeModifier, + }) + } + }; + + for c in modes { + match c { + '+' => cur_mod = Plus, + '-' => cur_mod = Minus, + _ => { + let mode = T::from_char(c); let arg = if mode.takes_arg() { - pieces.next() + // TODO: if there's no arg, this should error + args.next() } else { None }; - res.push(match init { - Plus => Mode::Plus(mode, arg.map(|s| s.to_owned())), - Minus => Mode::Minus(mode, arg.map(|s| s.to_owned())), + res.push(match cur_mod { + Plus => Mode::Plus(mode, arg.map(|s| s.to_string())), + Minus => Mode::Minus(mode, arg.map(|s| s.to_string())), }) } } } + // TODO: if there are extra args left, this should error + Ok(res) + } else { + Err(InvalidModeString { + string: pieces.join(" ").to_owned(), + cause: MissingModeModifier, + }) } } diff --git a/src/client/mod.rs b/src/client/mod.rs index 25206ee..ab4120a 100644 --- a/src/client/mod.rs +++ b/src/client/mod.rs @@ -570,11 +570,9 @@ impl ClientState { } } } - Command::Response(Response::RPL_NAMREPLY, ref args, ref suffix) => { - self.handle_namreply(args, suffix) - } - Command::Response(Response::RPL_ENDOFMOTD, _, _) - | Command::Response(Response::ERR_NOMOTD, _, _) => { + Command::Response(Response::RPL_NAMREPLY, ref args) => self.handle_namreply(args), + Command::Response(Response::RPL_ENDOFMOTD, _) + | Command::Response(Response::ERR_NOMOTD, _) => { self.send_nick_password()?; self.send_umodes()?; @@ -593,8 +591,8 @@ impl ClientState { self.send_join(chan)? } } - Command::Response(Response::ERR_NICKNAMEINUSE, _, _) - | Command::Response(Response::ERR_ERRONEOUSNICKNAME, _, _) => { + Command::Response(Response::ERR_NICKNAMEINUSE, _) + | Command::Response(Response::ERR_ERRONEOUSNICKNAME, _) => { let alt_nicks = self.config().alternate_nicknames(); let mut index = self.alt_nick_index.write(); @@ -623,20 +621,19 @@ impl ClientState { }; for s in seq { - self.send(NICKSERV(format!( - "{} {} {}", - s, - self.config().nickname()?, - self.config().nick_password() + self.send(NICKSERV(vec!( + s.to_string(), + self.config().nickname()?.to_string(), + self.config().nick_password().to_string(), )))?; } *index = 0; self.send(NICK(self.config().nickname()?.to_owned()))? } - self.send(NICKSERV(format!( - "IDENTIFY {}", - self.config().nick_password() + self.send(NICKSERV(vec!( + "IDENTIFY".to_string(), + self.config().nick_password().to_string() ))) } } @@ -647,15 +644,20 @@ impl ClientState { } else { self.send_mode( self.current_nickname(), - &Mode::as_user_modes(self.config().umodes()).map_err(|e| { - error::Error::InvalidMessage { - string: format!( - "MODE {} {}", - self.current_nickname(), - self.config().umodes() - ), - cause: e, - } + &Mode::as_user_modes( + self.config() + .umodes() + .split(' ') + .collect::>() + .as_ref(), + ) + .map_err(|e| error::Error::InvalidMessage { + string: format!( + "MODE {} {}", + self.current_nickname(), + self.config().umodes() + ), + cause: e, })?, ) } @@ -740,20 +742,18 @@ impl ClientState { } #[cfg(feature = "nochanlists")] - fn handle_namreply(&self, _: &[String], _: &Option) {} + fn handle_namreply(&self, _: &[String]) {} #[cfg(not(feature = "nochanlists"))] - fn handle_namreply(&self, args: &[String], suffix: &Option) { - if let Some(ref users) = *suffix { - if args.len() == 3 { - let chan = &args[2]; - for user in users.split(' ') { - self.chanlists - .write() - .entry(chan.clone()) - .or_insert_with(Vec::new) - .push(User::new(user)) - } + fn handle_namreply(&self, args: &[String]) { + if args.len() == 4 { + let chan = &args[2]; + for user in args[3].split(' ') { + self.chanlists + .write() + .entry(chan.clone()) + .or_insert_with(Vec::new) + .push(User::new(user)) } } } @@ -1219,8 +1219,8 @@ mod test { client.stream()?.collect().await?; assert_eq!( &get_client_value(client)[..], - "NICK :test2\r\nNICKSERV GHOST test password\r\n\ - NICK :test\r\nNICKSERV IDENTIFY password\r\nJOIN #test\r\nJOIN #test2\r\n" + "NICK test2\r\nNICKSERV GHOST test password\r\n\ + NICK test\r\nNICKSERV IDENTIFY password\r\nJOIN #test\r\nJOIN #test2\r\n" ); Ok(()) } @@ -1243,8 +1243,8 @@ mod test { client.stream()?.collect().await?; assert_eq!( &get_client_value(client)[..], - "NICK :test2\r\nNICKSERV RECOVER test password\ - \r\nNICKSERV RELEASE test password\r\nNICK :test\r\nNICKSERV IDENTIFY password\ + "NICK test2\r\nNICKSERV RECOVER test password\ + \r\nNICKSERV RELEASE test password\r\nNICK test\r\nNICKSERV IDENTIFY password\ \r\nJOIN #test\r\nJOIN #test2\r\n" ); Ok(()) @@ -1278,7 +1278,7 @@ mod test { }) .await?; client.stream()?.collect().await?; - assert_eq!(&get_client_value(client)[..], "NICK :test2\r\n"); + assert_eq!(&get_client_value(client)[..], "NICK test2\r\n"); Ok(()) } @@ -1332,10 +1332,10 @@ mod test { async fn send_raw_is_really_raw() -> Result<()> { let mut client = Client::from_config(test_config()).await?; assert!(client - .send(Raw("PASS".to_owned(), vec!["password".to_owned()], None)) + .send(Raw("PASS".to_owned(), vec!["password".to_owned()])) .is_ok()); assert!(client - .send(Raw("NICK".to_owned(), vec!["test".to_owned()], None)) + .send(Raw("NICK".to_owned(), vec!["test".to_owned()])) .is_ok()); client.stream()?.collect().await?; assert_eq!( @@ -1622,7 +1622,7 @@ mod test { #[tokio::test] #[cfg(feature = "ctcp")] async fn ctcp_ping_no_timestamp() -> Result<()> { - let value = ":test!test@test PRIVMSG test :\u{001}PING\u{001}\r\n"; + let value = ":test!test@test PRIVMSG test \u{001}PING\u{001}\r\n"; let mut client = Client::from_config(Config { mock_initial_value: Some(value.to_owned()), ..test_config() @@ -1640,8 +1640,8 @@ mod test { client.stream()?.collect().await?; assert_eq!( &get_client_value(client)[..], - "CAP END\r\nNICK :test\r\n\ - USER test 0 * :test\r\n" + "CAP END\r\nNICK test\r\n\ + USER test 0 * test\r\n" ); Ok(()) } @@ -1658,8 +1658,8 @@ mod test { client.stream()?.collect().await?; assert_eq!( &get_client_value(client)[..], - "CAP END\r\nPASS :password\r\nNICK :test\r\n\ - USER test 0 * :test\r\n" + "CAP END\r\nPASS password\r\nNICK test\r\n\ + USER test 0 * test\r\n" ); Ok(()) } @@ -1669,7 +1669,7 @@ mod test { let mut client = Client::from_config(test_config()).await?; client.send_pong("irc.test.net")?; client.stream()?.collect().await?; - assert_eq!(&get_client_value(client)[..], "PONG :irc.test.net\r\n"); + assert_eq!(&get_client_value(client)[..], "PONG irc.test.net\r\n"); Ok(()) } @@ -1699,7 +1699,7 @@ mod test { let mut client = Client::from_config(test_config()).await?; client.send_oper("test", "test")?; client.stream()?.collect().await?; - assert_eq!(&get_client_value(client)[..], "OPER test :test\r\n"); + assert_eq!(&get_client_value(client)[..], "OPER test test\r\n"); Ok(()) } @@ -1846,7 +1846,7 @@ mod test { client.stream()?.collect().await?; assert_eq!( &get_client_value(client)[..], - "PRIVMSG test :\u{001}MESSAGE\u{001}\r\n" + "PRIVMSG test \u{001}MESSAGE\u{001}\r\n" ); Ok(()) } @@ -1872,7 +1872,7 @@ mod test { client.stream()?.collect().await?; assert_eq!( &get_client_value(client)[..], - "PRIVMSG test :\u{001}FINGER\u{001}\r\n" + "PRIVMSG test \u{001}FINGER\u{001}\r\n" ); Ok(()) } @@ -1885,7 +1885,7 @@ mod test { client.stream()?.collect().await?; assert_eq!( &get_client_value(client)[..], - "PRIVMSG test :\u{001}VERSION\u{001}\r\n" + "PRIVMSG test \u{001}VERSION\u{001}\r\n" ); Ok(()) } @@ -1898,7 +1898,7 @@ mod test { client.stream()?.collect().await?; assert_eq!( &get_client_value(client)[..], - "PRIVMSG test :\u{001}SOURCE\u{001}\r\n" + "PRIVMSG test \u{001}SOURCE\u{001}\r\n" ); Ok(()) } @@ -1911,7 +1911,7 @@ mod test { client.stream()?.collect().await?; assert_eq!( &get_client_value(client)[..], - "PRIVMSG test :\u{001}USERINFO\u{001}\r\n" + "PRIVMSG test \u{001}USERINFO\u{001}\r\n" ); Ok(()) } @@ -1937,7 +1937,7 @@ mod test { client.stream()?.collect().await?; assert_eq!( &get_client_value(client)[..], - "PRIVMSG test :\u{001}TIME\u{001}\r\n" + "PRIVMSG test \u{001}TIME\u{001}\r\n" ); Ok(()) }