Handle suffix as a plain param
This commit is contained in:
parent
2339ca5fe6
commit
f785d15b4c
5 changed files with 647 additions and 1322 deletions
File diff suppressed because it is too large
Load diff
|
@ -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, MessageParseError> {
|
||||
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<Message, error::MessageParseError> {
|
||||
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();
|
||||
|
|
|
@ -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<UserMode> {
|
||||
// TODO: turning more edge cases into errors.
|
||||
/// Parses the specified mode string as user modes.
|
||||
pub fn as_user_modes(s: &str) -> Result<Vec<Mode<UserMode>>, 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<Vec<Mode<UserMode>>, MessageParseError> {
|
||||
parse_modes(pieces)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -302,48 +260,67 @@ impl Mode<UserMode> {
|
|||
impl Mode<ChannelMode> {
|
||||
// TODO: turning more edge cases into errors.
|
||||
/// Parses the specified mode string as channel modes.
|
||||
pub fn as_channel_modes(s: &str) -> Result<Vec<Mode<ChannelMode>>, MessageParseError> {
|
||||
use self::PlusMinus::*;
|
||||
pub fn as_channel_modes(pieces: &[&str]) -> Result<Vec<Mode<ChannelMode>>, 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<T>(pieces: &[&str]) -> Result<Vec<Mode<T>>, 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,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue