From c44ec0984ecbdbe80ad3d493c4edca2f27773d32 Mon Sep 17 00:00:00 2001 From: Frankie Bagnardi Date: Mon, 17 Sep 2018 02:49:00 -0700 Subject: [PATCH 1/9] Prefix with FromStr and Display --- irc-proto/src/lib.rs | 2 + src/client/prelude.rs | 2 +- src/proto/prefix.rs | 170 ++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 173 insertions(+), 1 deletion(-) create mode 100644 src/proto/prefix.rs diff --git a/irc-proto/src/lib.rs b/irc-proto/src/lib.rs index dd875e55..09e5bba6 100644 --- a/irc-proto/src/lib.rs +++ b/irc-proto/src/lib.rs @@ -23,6 +23,7 @@ pub mod irc; pub mod line; pub mod message; pub mod mode; +pub mod prefix; pub mod response; pub use self::caps::{Capability, NegotiationVersion}; @@ -33,4 +34,5 @@ pub use self::command::{BatchSubCommand, CapSubCommand, Command}; pub use self::irc::IrcCodec; pub use self::message::Message; pub use self::mode::{ChannelMode, Mode, UserMode}; +pub use self::prefix::Prefix; pub use self::response::Response; diff --git a/src/client/prelude.rs b/src/client/prelude.rs index ef92e0cc..bda4efa8 100644 --- a/src/client/prelude.rs +++ b/src/client/prelude.rs @@ -25,7 +25,7 @@ pub use client::data::Config; pub use client::reactor::IrcReactor; pub use client::{EachIncomingExt, IrcClient, Client}; pub use client::ext::ClientExt; -pub use proto::{Capability, ChannelExt, Command, Message, NegotiationVersion, Response}; +pub use proto::{Capability, ChannelExt, Command, Message, Prefix, NegotiationVersion, Response}; pub use proto::{ChannelMode, Mode, UserMode}; pub use futures::{Future, Stream}; diff --git a/src/proto/prefix.rs b/src/proto/prefix.rs new file mode 100644 index 00000000..5da107b9 --- /dev/null +++ b/src/proto/prefix.rs @@ -0,0 +1,170 @@ +//! A module providing an enum for a message prefix. +use std::borrow::ToOwned; +use std::string; +use std::str::FromStr; +use std::fmt; + +/// The Prefix indicates "the true origin of the message", according to the server. +/// It will +#[derive(Clone, Eq, PartialEq, Debug)] +pub enum Prefix { + /// servername + ServerName(String), + /// nickname [ ["!" username] "@" hostname ] + Nickname(String, Option, Option), +} + +impl Prefix { + /// Creates a prefix by parsing a string. + /// + /// #Example + /// ``` + /// # extern crate irc; + /// # use irc::client::prelude::*; + /// # fn main() { + /// Prefix::new_from_str("nickname!username@hostname"); + /// Prefix::new_from_str("example.com"); + /// # } + /// ``` + pub fn new_from_str(s: &str) -> Prefix { + let mut name = String::new(); + let mut user = None; + let mut host = None; + + for c in s.chars() { + match c { + '.' if user.is_none() && host.is_none() => return Prefix::ServerName(s.to_owned()), + '!' if user.is_none() => { + user = Some(String::new()) + }, + '@' if user.is_some() && host.is_none() => { + host = Some(String::new()) + }, + _ => { + if host.is_some() { + host.as_mut().unwrap().push(c) + } else if user.is_some() { + user.as_mut().unwrap().push(c) + } else { + name.push(c) + } + } + } + } + + Prefix::Nickname(name, user, host) + } +} + +impl FromStr for Prefix { + type Err = string::ParseError; + + fn from_str(s: &str) -> Result { + Ok(Prefix::new_from_str(s)) + } +} + +impl fmt::Display for Prefix { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match self { + Prefix::ServerName(name) => write!(f, "{}", name), + Prefix::Nickname(name, None, None) => write!(f, "{}", name), + Prefix::Nickname(name, Some(user), None) => write!(f, "{}!{}", name, user), + Prefix::Nickname(name, Some(user), Some(host)) => write!(f, "{}!{}@{}", name, user, host), + // This is an issue with the type using two Option values when really host implies user + // Maybe this should do the same as the (name, None, None) case + Prefix::Nickname(_, None, Some(_)) => panic!("can't display prefix with host but not username"), + } + } +} + +impl<'a> From<&'a str> for Prefix { + fn from(s: &str) -> Self { + Prefix::new_from_str(s) + } +} + +#[cfg(test)] +mod test { + use super::Prefix::{self, ServerName, Nickname}; + + // Checks that str -> parsed -> Display doesn't lose data + fn test_parse(s: &str) -> Prefix { + let prefix = Prefix::new_from_str(s); + let s2 = format!("{}", prefix); + assert_eq!(s, &s2); + prefix + } + + #[test] + fn parse_word() { + assert_eq!( + test_parse("only_nick"), + Nickname("only_nick".into(), None, None) + ) + } + + #[test] + fn parse_host() { + assert_eq!( + test_parse("host.tld"), + ServerName("host.tld".into()) + ) + } + + #[test] + fn parse_nick_user() { + assert_eq!( + test_parse("test!nick"), + Nickname("test".into(), Some("nick".into()), None) + ) + } + + #[test] + fn parse_nick_user_host() { + assert_eq!( + test_parse("test!nick@host"), + Nickname("test".into(), Some("nick".into()), Some("host".into())) + ) + } + + #[test] + fn parse_dot_and_symbols() { + assert_eq!( + test_parse("test.net@something"), + ServerName("test.net@something".into()) + ) + } + + #[test] + fn parse_danger_cases() { + assert_eq!( + test_parse("name@name!user"), + Nickname("name@name".into(), Some("user".into()), None) + ); + assert_eq!( + test_parse("name!@"), + Nickname("name".into(), Some("".into()), Some("".into())) + ); + assert_eq!( + test_parse("name!.user"), + Nickname("name".into(), Some(".user".into()), None) + ); + assert_eq!( + test_parse("name!user.user"), + Nickname("name".into(), Some("user.user".into()), None) + ); + assert_eq!( + test_parse("name!user@host.host"), + Nickname("name".into(), Some("user".into()), Some("host.host".into())) + ); + assert_eq!( + test_parse("!user"), + Nickname("".into(), Some("user".into()), None) + ); + assert_eq!( + test_parse("!@host.host"), + Nickname("".into(), Some("".into()), Some("host.host".into())) + ); + } +} From 5e723425e3c5f57cc2d2ab53bf61077d238b92b8 Mon Sep 17 00:00:00 2001 From: Frankie Bagnardi Date: Mon, 17 Sep 2018 04:52:22 -0700 Subject: [PATCH 2/9] proto::message uses Prefix --- irc-proto/src/message.rs | 37 ++++++++++++++----------------------- 1 file changed, 14 insertions(+), 23 deletions(-) diff --git a/irc-proto/src/message.rs b/irc-proto/src/message.rs index 86f837c0..5b01e117 100644 --- a/irc-proto/src/message.rs +++ b/irc-proto/src/message.rs @@ -1,12 +1,11 @@ //! A module providing a data structure for messages to and from IRC servers. use std::borrow::ToOwned; -use std::fmt::{Display, Formatter, Result as FmtResult}; +use std::fmt::{Display, Formatter, Result as FmtResult, Write}; use std::str::FromStr; use error; -use error::{ProtocolError, MessageParseError}; -use chan::ChannelExt; -use command::Command; +use error::{IrcError, MessageParseError, ProtocolError, MessageParseError}; +use proto::{Command, ChannelExt, Prefix}; /// A data structure representing an IRC message according to the protocol specification. It /// consists of a collection of IRCv3 tags, a prefix (describing the source of the message), and @@ -20,7 +19,7 @@ pub struct Message { /// in IRCv3 extensions to the IRC protocol. pub tags: Option>, /// The message prefix (or source) as defined by [RFC 2812](http://tools.ietf.org/html/rfc2812). - pub prefix: Option, + pub prefix: Option, /// The IRC command, parsed according to the known specifications. The command itself and its /// arguments (including the special suffix argument) are captured in this component. pub command: Command, @@ -60,7 +59,7 @@ impl Message { ) -> Result { Ok(Message { tags: tags, - prefix: prefix.map(|s| s.to_owned()), + prefix: prefix.map(|p| p.into()), command: Command::new(command, args, suffix)?, }) } @@ -81,15 +80,9 @@ impl Message { pub fn source_nickname(&self) -> Option<&str> { // ::= | [ '!' ] [ '@' ] // ::= - self.prefix.as_ref().and_then(|s| match ( - s.find('!'), - s.find('@'), - s.find('.'), - ) { - (Some(i), _, _) | // '!' [ '@' ] - (None, Some(i), _) => Some(&s[..i]), // '@' - (None, None, None) => Some(s), // - _ => None, // + self.prefix.as_ref().and_then(|p| match p { + Prefix::Nickname(name, _, _) => Some(&name[..]), + _ => None }) } @@ -149,9 +142,7 @@ impl Message { ret.push(' '); } if let Some(ref prefix) = self.prefix { - ret.push(':'); - ret.push_str(prefix); - ret.push(' '); + write!(ret, ":{} ", prefix).unwrap(); } let cmd: String = From::from(&self.command); ret.push_str(&cmd); @@ -362,7 +353,7 @@ mod test { assert_eq!(&message.to_string()[..], "PRIVMSG test :Testing!\r\n"); let message = Message { tags: None, - prefix: Some(format!("test!test@test")), + prefix: Some("test!test@test".into()), command: PRIVMSG(format!("test"), format!("Still testing!")), }; assert_eq!( @@ -384,7 +375,7 @@ mod test { ); let message = Message { tags: None, - prefix: Some(format!("test!test@test")), + prefix: Some("test!test@test".into()), command: PRIVMSG(format!("test"), format!("Still testing!")), }; assert_eq!( @@ -399,7 +390,7 @@ mod test { Tag(format!("ccc"), None), Tag(format!("example.com/ddd"), Some(format!("eee"))), ]), - prefix: Some(format!("test!test@test")), + prefix: Some("test!test@test".into()), command: PRIVMSG(format!("test"), format!("Testing with tags!")), }; assert_eq!( @@ -450,7 +441,7 @@ mod test { assert_eq!(msg, message); let message = Message { tags: None, - prefix: Some(format!("test!test@test")), + prefix: Some("test!test@test".into()), command: PRIVMSG(format!("test"), format!("Still testing!")), }; let msg: Message = ":test!test@test PRIVMSG test :Still testing!\r\n".into(); @@ -463,7 +454,7 @@ mod test { // colons within individual parameters. So, let's make sure it parses correctly. let message = Message { tags: None, - prefix: Some(format!("test!test@test")), + prefix: Some("test!test@test".into()), command: Raw( format!("COMMAND"), vec![format!("ARG:test")], From 140c981e634db33dc31b1d3d87012e1432b1caa7 Mon Sep 17 00:00:00 2001 From: Frankie Bagnardi Date: Mon, 17 Sep 2018 05:23:12 -0700 Subject: [PATCH 3/9] prefix cleanup and docs --- src/proto/prefix.rs | 30 +++++++++++++++++++++++------- 1 file changed, 23 insertions(+), 7 deletions(-) diff --git a/src/proto/prefix.rs b/src/proto/prefix.rs index 5da107b9..7fd9742f 100644 --- a/src/proto/prefix.rs +++ b/src/proto/prefix.rs @@ -5,7 +5,9 @@ use std::str::FromStr; use std::fmt; /// The Prefix indicates "the true origin of the message", according to the server. -/// It will +/// +/// Warning: Avoid constructing a `Nickname(nickname, None, Some(hostname))`, but +/// `Nickname(nickname, Some("".to_owned()), Some(hostname))` works reliably. #[derive(Clone, Eq, PartialEq, Debug)] pub enum Prefix { /// servername @@ -16,8 +18,8 @@ pub enum Prefix { impl Prefix { /// Creates a prefix by parsing a string. - /// - /// #Example + /// + /// # Example /// ``` /// # extern crate irc; /// # use irc::client::prelude::*; @@ -33,14 +35,22 @@ impl Prefix { for c in s.chars() { match c { - '.' if user.is_none() && host.is_none() => return Prefix::ServerName(s.to_owned()), + // We consider the '.' to be a ServerName except if a ! has already + // been encountered. + '.' if user.is_none() => return Prefix::ServerName(s.to_owned()), + '!' if user.is_none() => { user = Some(String::new()) }, + + // The '@' is not special until we've started the username + // portion '@' if user.is_some() && host.is_none() => { host = Some(String::new()) }, + _ => { + // Push onto the latest buffer if host.is_some() { host.as_mut().unwrap().push(c) } else if user.is_some() { @@ -56,6 +66,7 @@ impl Prefix { } } +/// This implementation never returns an error and is isomorphic with `Display`. impl FromStr for Prefix { type Err = string::ParseError; @@ -64,6 +75,7 @@ impl FromStr for Prefix { } } +/// This is isomorphic with `FromStr`, except when called on `Prefix::Nickname(nickname, None, Some(hostname))` impl fmt::Display for Prefix { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match self { @@ -71,9 +83,9 @@ impl fmt::Display for Prefix { Prefix::Nickname(name, None, None) => write!(f, "{}", name), Prefix::Nickname(name, Some(user), None) => write!(f, "{}!{}", name, user), Prefix::Nickname(name, Some(user), Some(host)) => write!(f, "{}!{}@{}", name, user, host), - // This is an issue with the type using two Option values when really host implies user - // Maybe this should do the same as the (name, None, None) case - Prefix::Nickname(_, None, Some(_)) => panic!("can't display prefix with host but not username"), + + // This is an issue with the type using two Option values when really hostname implies username + Prefix::Nickname(name, None, Some(host)) => write!(f, "{}!@{}", name, host), } } } @@ -146,6 +158,10 @@ mod test { test_parse("name!@"), Nickname("name".into(), Some("".into()), Some("".into())) ); + assert_eq!( + test_parse("name!@hostname"), + Nickname("name".into(), Some("".into()), Some("hostname".into())) + ); assert_eq!( test_parse("name!.user"), Nickname("name".into(), Some(".user".into()), None) From f66dcd6b0a0ff4d26472ef0ce04436298e99d5d1 Mon Sep 17 00:00:00 2001 From: Frankie Bagnardi Date: Mon, 17 Sep 2018 22:03:22 -0700 Subject: [PATCH 4/9] rebased --- irc-proto/src/message.rs | 7 +++++-- {src/proto => irc-proto/src}/prefix.rs | 0 2 files changed, 5 insertions(+), 2 deletions(-) rename {src/proto => irc-proto/src}/prefix.rs (100%) diff --git a/irc-proto/src/message.rs b/irc-proto/src/message.rs index 5b01e117..b2648d71 100644 --- a/irc-proto/src/message.rs +++ b/irc-proto/src/message.rs @@ -3,9 +3,12 @@ use std::borrow::ToOwned; use std::fmt::{Display, Formatter, Result as FmtResult, Write}; use std::str::FromStr; +use chan::ChannelExt; +use command::Command; use error; -use error::{IrcError, MessageParseError, ProtocolError, MessageParseError}; -use proto::{Command, ChannelExt, Prefix}; +use error::{MessageParseError, ProtocolError}; +use prefix::Prefix; + /// A data structure representing an IRC message according to the protocol specification. It /// consists of a collection of IRCv3 tags, a prefix (describing the source of the message), and diff --git a/src/proto/prefix.rs b/irc-proto/src/prefix.rs similarity index 100% rename from src/proto/prefix.rs rename to irc-proto/src/prefix.rs From ddcd120313edd0548b58fbbadc3ba8c1faf25afc Mon Sep 17 00:00:00 2001 From: Frankie Bagnardi Date: Mon, 17 Sep 2018 22:36:36 -0700 Subject: [PATCH 5/9] prefix uses Nickname(String, String, String) --- irc-proto/src/prefix.rs | 85 +++++++++++++++++++++++++---------------- 1 file changed, 52 insertions(+), 33 deletions(-) diff --git a/irc-proto/src/prefix.rs b/irc-proto/src/prefix.rs index 7fd9742f..b4fa8897 100644 --- a/irc-proto/src/prefix.rs +++ b/irc-proto/src/prefix.rs @@ -13,7 +13,7 @@ pub enum Prefix { /// servername ServerName(String), /// nickname [ ["!" username] "@" hostname ] - Nickname(String, Option, Option), + Nickname(String, String, String), } impl Prefix { @@ -29,35 +29,41 @@ impl Prefix { /// # } /// ``` pub fn new_from_str(s: &str) -> Prefix { + #[derive(Copy, Clone, Eq, PartialEq)] + enum Active { + Name = 0, + User = 1, + Host = 2, + } + let mut name = String::new(); - let mut user = None; - let mut host = None; + let mut user = String::new(); + let mut host = String::new(); + let mut active = Active::Name; for c in s.chars() { match c { // We consider the '.' to be a ServerName except if a ! has already // been encountered. - '.' if user.is_none() => return Prefix::ServerName(s.to_owned()), + '.' if active == Active::Name => return Prefix::ServerName(s.to_owned()), - '!' if user.is_none() => { - user = Some(String::new()) + '!' if active == Active::Name => { + active = Active::User; }, // The '@' is not special until we've started the username // portion - '@' if user.is_some() && host.is_none() => { - host = Some(String::new()) + '@' if active == Active::User => { + active = Active::Host; }, _ => { // Push onto the latest buffer - if host.is_some() { - host.as_mut().unwrap().push(c) - } else if user.is_some() { - user.as_mut().unwrap().push(c) - } else { - name.push(c) - } + match active { + Active::Name => &mut name, + Active::User => &mut user, + Active::Host => &mut host, + }.push(c) } } } @@ -75,17 +81,20 @@ impl FromStr for Prefix { } } -/// This is isomorphic with `FromStr`, except when called on `Prefix::Nickname(nickname, None, Some(hostname))` +/// This is isomorphic with `FromStr` impl fmt::Display for Prefix { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match self { Prefix::ServerName(name) => write!(f, "{}", name), - Prefix::Nickname(name, None, None) => write!(f, "{}", name), - Prefix::Nickname(name, Some(user), None) => write!(f, "{}!{}", name, user), - Prefix::Nickname(name, Some(user), Some(host)) => write!(f, "{}!{}@{}", name, user, host), - - // This is an issue with the type using two Option values when really hostname implies username - Prefix::Nickname(name, None, Some(host)) => write!(f, "{}!@{}", name, host), + Prefix::Nickname(name, user, host) => match (&name[..], &user[..], &host[..]) { + ("", "", "") => write!(f, ""), + (name, "", "") => write!(f, "{}", name), + (name, user, "") => write!(f, "{}!{}", name, user), + // This case shouldn't happen normally, but user!@host is invalid, so we + // format it without the host + (name, "", _host) => write!(f, "{}", name), + (name, user, host) => write!(f, "{}!{}@{}", name, user, host), + }, } } } @@ -108,11 +117,21 @@ mod test { prefix } + #[test] + fn print() { + let s = format!("{}", Nickname("nick".into(), "".into(), "".into())); + assert_eq!(&s, "nick"); + let s = format!("{}", Nickname("nick".into(), "user".into(), "".into())); + assert_eq!(&s, "nick!user"); + let s = format!("{}", Nickname("nick".into(), "user".into(), "host".into())); + assert_eq!(&s, "nick!user@host"); + } + #[test] fn parse_word() { assert_eq!( test_parse("only_nick"), - Nickname("only_nick".into(), None, None) + Nickname("only_nick".into(), String::new(), String::new()) ) } @@ -128,7 +147,7 @@ mod test { fn parse_nick_user() { assert_eq!( test_parse("test!nick"), - Nickname("test".into(), Some("nick".into()), None) + Nickname("test".into(), "nick".into(), String::new()) ) } @@ -136,7 +155,7 @@ mod test { fn parse_nick_user_host() { assert_eq!( test_parse("test!nick@host"), - Nickname("test".into(), Some("nick".into()), Some("host".into())) + Nickname("test".into(), "nick".into(), "host".into()) ) } @@ -152,35 +171,35 @@ mod test { fn parse_danger_cases() { assert_eq!( test_parse("name@name!user"), - Nickname("name@name".into(), Some("user".into()), None) + Nickname("name@name".into(), "user".into(), String::new()) ); assert_eq!( test_parse("name!@"), - Nickname("name".into(), Some("".into()), Some("".into())) + Nickname("name".into(), "".into(), "".into()) ); assert_eq!( test_parse("name!@hostname"), - Nickname("name".into(), Some("".into()), Some("hostname".into())) + Nickname("name".into(), "".into(), "hostname".into()) ); assert_eq!( test_parse("name!.user"), - Nickname("name".into(), Some(".user".into()), None) + Nickname("name".into(), ".user".into(), String::new()) ); assert_eq!( test_parse("name!user.user"), - Nickname("name".into(), Some("user.user".into()), None) + Nickname("name".into(), "user.user".into(), String::new()) ); assert_eq!( test_parse("name!user@host.host"), - Nickname("name".into(), Some("user".into()), Some("host.host".into())) + Nickname("name".into(), "user".into(), "host.host".into()) ); assert_eq!( test_parse("!user"), - Nickname("".into(), Some("user".into()), None) + Nickname("".into(), "user".into(), String::new()) ); assert_eq!( test_parse("!@host.host"), - Nickname("".into(), Some("".into()), Some("host.host".into())) + Nickname("".into(), "".into(), "host.host".into()) ); } } From 4728e85e0ee71550154884d3d009e1953ff4b7b4 Mon Sep 17 00:00:00 2001 From: Frankie Bagnardi Date: Mon, 17 Sep 2018 22:39:48 -0700 Subject: [PATCH 6/9] prefix docs --- irc-proto/src/prefix.rs | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/irc-proto/src/prefix.rs b/irc-proto/src/prefix.rs index b4fa8897..d04c2790 100644 --- a/irc-proto/src/prefix.rs +++ b/irc-proto/src/prefix.rs @@ -5,14 +5,13 @@ use std::str::FromStr; use std::fmt; /// The Prefix indicates "the true origin of the message", according to the server. -/// -/// Warning: Avoid constructing a `Nickname(nickname, None, Some(hostname))`, but -/// `Nickname(nickname, Some("".to_owned()), Some(hostname))` works reliably. #[derive(Clone, Eq, PartialEq, Debug)] pub enum Prefix { - /// servername + /// servername, e.g. collins.mozilla.org ServerName(String), /// nickname [ ["!" username] "@" hostname ] + /// i.e. Nickname(nickname, username, hostname) + /// Any of the strings may be "" Nickname(String, String, String), } From 5a50e4eea8958065874fedb0bd6b381ffd045837 Mon Sep 17 00:00:00 2001 From: Frankie Bagnardi Date: Mon, 17 Sep 2018 23:55:35 -0700 Subject: [PATCH 7/9] WIP prefix fixes --- irc-proto/src/prefix.rs | 36 ++++++++++++++++++++---------------- 1 file changed, 20 insertions(+), 16 deletions(-) diff --git a/irc-proto/src/prefix.rs b/irc-proto/src/prefix.rs index d04c2790..f31ec25e 100644 --- a/irc-proto/src/prefix.rs +++ b/irc-proto/src/prefix.rs @@ -1,5 +1,4 @@ //! A module providing an enum for a message prefix. -use std::borrow::ToOwned; use std::string; use std::str::FromStr; use std::fmt; @@ -30,34 +29,37 @@ impl Prefix { pub fn new_from_str(s: &str) -> Prefix { #[derive(Copy, Clone, Eq, PartialEq)] enum Active { - Name = 0, - User = 1, - Host = 2, + Name, + User, + Host, } let mut name = String::new(); let mut user = String::new(); let mut host = String::new(); let mut active = Active::Name; + let mut is_server = false; for c in s.chars() { - match c { - // We consider the '.' to be a ServerName except if a ! has already - // been encountered. - '.' if active == Active::Name => return Prefix::ServerName(s.to_owned()), + if c == '.' { + // We won't return Nickname("nick", "", "") but if @ or ! are + // encountered, then we set this back to false + is_server = true; + } + match c { '!' if active == Active::Name => { + is_server = false; active = Active::User; }, - // The '@' is not special until we've started the username - // portion - '@' if active == Active::User => { + '@' if active != Active::Host => { + is_server = false; active = Active::Host; }, _ => { - // Push onto the latest buffer + // Push onto the active buffer match active { Active::Name => &mut name, Active::User => &mut user, @@ -67,7 +69,11 @@ impl Prefix { } } - Prefix::Nickname(name, user, host) + if is_server { + Prefix::ServerName(name) + } else { + Prefix::Nickname(name, user, host) + } } } @@ -89,9 +95,7 @@ impl fmt::Display for Prefix { ("", "", "") => write!(f, ""), (name, "", "") => write!(f, "{}", name), (name, user, "") => write!(f, "{}!{}", name, user), - // This case shouldn't happen normally, but user!@host is invalid, so we - // format it without the host - (name, "", _host) => write!(f, "{}", name), + (name, "", host) => write!(f, "{}@{}", name, host), (name, user, host) => write!(f, "{}!{}@{}", name, user, host), }, } From c9e6f6663f92ba994e65dfae31cb5197e0b8eb92 Mon Sep 17 00:00:00 2001 From: Frankie Bagnardi Date: Tue, 18 Sep 2018 00:14:33 -0700 Subject: [PATCH 8/9] fixes issues from review --- irc-proto/src/prefix.rs | 24 +++++++++++++----------- 1 file changed, 13 insertions(+), 11 deletions(-) diff --git a/irc-proto/src/prefix.rs b/irc-proto/src/prefix.rs index f31ec25e..7d351504 100644 --- a/irc-proto/src/prefix.rs +++ b/irc-proto/src/prefix.rs @@ -19,8 +19,8 @@ impl Prefix { /// /// # Example /// ``` - /// # extern crate irc; - /// # use irc::client::prelude::*; + /// # extern crate irc_proto; + /// # use irc_proto::Prefix; /// # fn main() { /// Prefix::new_from_str("nickname!username@hostname"); /// Prefix::new_from_str("example.com"); @@ -41,7 +41,7 @@ impl Prefix { let mut is_server = false; for c in s.chars() { - if c == '.' { + if c == '.' && active == Active::Name { // We won't return Nickname("nick", "", "") but if @ or ! are // encountered, then we set this back to false is_server = true; @@ -166,7 +166,7 @@ mod test { fn parse_dot_and_symbols() { assert_eq!( test_parse("test.net@something"), - ServerName("test.net@something".into()) + Nickname("test.net".into(), "".into(), "something".into()) ) } @@ -174,23 +174,25 @@ mod test { fn parse_danger_cases() { assert_eq!( test_parse("name@name!user"), - Nickname("name@name".into(), "user".into(), String::new()) + Nickname("name".into(), "".into(), "name!user".into()) ); assert_eq!( - test_parse("name!@"), + // can't reverse the parse + "name!@".parse::().unwrap(), Nickname("name".into(), "".into(), "".into()) ); assert_eq!( - test_parse("name!@hostname"), + // can't reverse the parse + "name!@hostname".parse::().unwrap(), Nickname("name".into(), "".into(), "hostname".into()) ); assert_eq!( test_parse("name!.user"), - Nickname("name".into(), ".user".into(), String::new()) + Nickname("name".into(), ".user".into(), "".into()) ); assert_eq!( test_parse("name!user.user"), - Nickname("name".into(), "user.user".into(), String::new()) + Nickname("name".into(), "user.user".into(), "".into()) ); assert_eq!( test_parse("name!user@host.host"), @@ -198,10 +200,10 @@ mod test { ); assert_eq!( test_parse("!user"), - Nickname("".into(), "user".into(), String::new()) + Nickname("".into(), "user".into(), "".into()) ); assert_eq!( - test_parse("!@host.host"), + "!@host.host".parse::().unwrap(), Nickname("".into(), "".into(), "host.host".into()) ); } From 687b374801ea5d597a62038b760d4bfd6b62d874 Mon Sep 17 00:00:00 2001 From: Frankie Bagnardi Date: Tue, 18 Sep 2018 00:16:23 -0700 Subject: [PATCH 9/9] ParseError -> () --- irc-proto/src/prefix.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/irc-proto/src/prefix.rs b/irc-proto/src/prefix.rs index 7d351504..9de076e5 100644 --- a/irc-proto/src/prefix.rs +++ b/irc-proto/src/prefix.rs @@ -1,5 +1,4 @@ //! A module providing an enum for a message prefix. -use std::string; use std::str::FromStr; use std::fmt; @@ -79,7 +78,7 @@ impl Prefix { /// This implementation never returns an error and is isomorphic with `Display`. impl FromStr for Prefix { - type Err = string::ParseError; + type Err = (); fn from_str(s: &str) -> Result { Ok(Prefix::new_from_str(s))