Updated for Rust master.

This commit is contained in:
Aaron Weiss 2015-02-03 13:11:33 -05:00
parent 3a85ad2708
commit 2f79f180d8
11 changed files with 47 additions and 48 deletions

View file

@ -1,5 +1,4 @@
#![allow(unstable)] #![feature(core, slicing_syntax, std_misc)]
#![feature(slicing_syntax)]
extern crate irc; extern crate irc;
use std::default::Default; use std::default::Default;

View file

@ -1,5 +1,4 @@
#![allow(unstable)] #![feature(core, slicing_syntax, std_misc)]
#![feature(slicing_syntax)]
extern crate irc; extern crate irc;
use std::default::Default; use std::default::Default;

View file

@ -1,5 +1,4 @@
#![allow(unstable)] #![feature(core, slicing_syntax)]
#![feature(slicing_syntax)]
extern crate irc; extern crate irc;
use std::default::Default; use std::default::Default;

View file

@ -1,5 +1,4 @@
#![allow(unstable)] #![feature(core, slicing_syntax)]
#![feature(slicing_syntax)]
extern crate irc; extern crate irc;
use std::default::Default; use std::default::Default;

View file

@ -1,5 +1,4 @@
#![feature(slicing_syntax)] #![feature(io, slicing_syntax, std_misc)]
#![allow(unstable)]
extern crate irc; extern crate irc;
use std::default::Default; use std::default::Default;

View file

@ -9,7 +9,7 @@ use client::data::message::{Message, ToMessage};
/// [capabilities extension](https://tools.ietf.org/html/draft-mitchell-irc-capabilities-01). /// [capabilities extension](https://tools.ietf.org/html/draft-mitchell-irc-capabilities-01).
/// Additionally, this includes some common additional commands from popular IRCds. /// Additionally, this includes some common additional commands from popular IRCds.
#[stable] #[stable]
#[derive(Show, PartialEq)] #[derive(Debug, PartialEq)]
pub enum Command<'a> { pub enum Command<'a> {
// 3.1 Connection Registration // 3.1 Connection Registration
/// PASS :password /// PASS :password
@ -992,7 +992,7 @@ impl<'a> Command<'a> {
} }
} else if let "CAP" = &m.command[] { } else if let "CAP" = &m.command[] {
if m.args.len() != 1 { return Err(invalid_input()) } if m.args.len() != 1 { return Err(invalid_input()) }
if let Some(cmd) = m.args[0].parse() { if let Ok(cmd) = m.args[0].parse() {
match m.suffix { match m.suffix {
Some(ref suffix) => Command::CAP(cmd, Some(&suffix[])), Some(ref suffix) => Command::CAP(cmd, Some(&suffix[])),
None => Command::CAP(cmd, None), None => Command::CAP(cmd, None),
@ -1008,7 +1008,7 @@ impl<'a> Command<'a> {
/// A list of all of the subcommands for the capabilities extension. /// A list of all of the subcommands for the capabilities extension.
#[stable] #[stable]
#[derive(Copy, Show, PartialEq)] #[derive(Copy, Debug, PartialEq)]
pub enum CapSubCommand { pub enum CapSubCommand {
/// Requests a list of the server's capabilities. /// Requests a list of the server's capabilities.
#[stable] #[stable]
@ -1051,16 +1051,17 @@ impl CapSubCommand {
} }
impl FromStr for CapSubCommand { impl FromStr for CapSubCommand {
fn from_str(s: &str) -> Option<CapSubCommand> { type Err = &'static str;
fn from_str(s: &str) -> Result<CapSubCommand, &'static str> {
match s { match s {
"LS" => Some(CapSubCommand::LS), "LS" => Ok(CapSubCommand::LS),
"LIST" => Some(CapSubCommand::LIST), "LIST" => Ok(CapSubCommand::LIST),
"REQ" => Some(CapSubCommand::REQ), "REQ" => Ok(CapSubCommand::REQ),
"ACK" => Some(CapSubCommand::ACK), "ACK" => Ok(CapSubCommand::ACK),
"NAK" => Some(CapSubCommand::NAK), "NAK" => Ok(CapSubCommand::NAK),
"CLEAR" => Some(CapSubCommand::CLEAR), "CLEAR" => Ok(CapSubCommand::CLEAR),
"END" => Some(CapSubCommand::END), "END" => Ok(CapSubCommand::END),
_ => None, _ => Err("Failed to parse CAP subcommand."),
} }
} }
} }

View file

@ -8,7 +8,7 @@ use std::old_io::{InvalidInput, IoError, IoResult};
use rustc_serialize::json::decode; use rustc_serialize::json::decode;
/// Configuration data. /// Configuration data.
#[derive(Clone, RustcDecodable, Default, PartialEq, Show)] #[derive(Clone, RustcDecodable, Default, PartialEq, Debug)]
#[stable] #[stable]
pub struct Config { pub struct Config {
/// A list of the owners of the bot by nickname. /// A list of the owners of the bot by nickname.

View file

@ -5,7 +5,7 @@ use std::str::FromStr;
/// IRC Message data. /// IRC Message data.
#[stable] #[stable]
#[derive(Clone, PartialEq, Show)] #[derive(Clone, PartialEq, Debug)]
pub struct Message { pub struct Message {
/// The message prefix (or source) as defined by [RFC 2812](http://tools.ietf.org/html/rfc2812). /// The message prefix (or source) as defined by [RFC 2812](http://tools.ietf.org/html/rfc2812).
#[stable] #[stable]
@ -72,9 +72,10 @@ impl ToMessage for Message {
} }
impl FromStr for Message { impl FromStr for Message {
fn from_str(s: &str) -> Option<Message> { type Err = &'static str;
fn from_str(s: &str) -> Result<Message, &'static str> {
let mut state = s.clone(); let mut state = s.clone();
if s.len() == 0 { return None } if s.len() == 0 { return Err("Cannot parse an empty string as a message.") }
let prefix = if state.starts_with(":") { let prefix = if state.starts_with(":") {
let prefix = state.find(' ').map(|i| &state[1..i]); let prefix = state.find(' ').map(|i| &state[1..i]);
state = state.find(' ').map_or("", |i| &state[i+1..]); state = state.find(' ').map_or("", |i| &state[i+1..]);
@ -94,11 +95,11 @@ impl FromStr for Message {
state = state.find(' ').map_or("", |i| &state[i+1..]); state = state.find(' ').map_or("", |i| &state[i+1..]);
cmd cmd
} }
_ => return None _ => return Err("Cannot parse a message without a command.")
}; };
if suffix.is_none() { state = &state[..state.len() - 2] } if suffix.is_none() { state = &state[..state.len() - 2] }
let args: Vec<_> = state.splitn(14, ' ').filter(|s| s.len() != 0).collect(); let args: Vec<_> = state.splitn(14, ' ').filter(|s| s.len() != 0).collect();
Some(Message::new(prefix, command, if args.len() > 0 { Some(args) } else { None }, suffix)) Ok(Message::new(prefix, command, if args.len() > 0 { Some(args) } else { None }, suffix))
} }
} }
@ -167,14 +168,14 @@ mod test {
args: vec![format!("test")], args: vec![format!("test")],
suffix: Some(format!("Testing!")), suffix: Some(format!("Testing!")),
}; };
assert_eq!("PRIVMSG test :Testing!\r\n".parse(), Some(message)); assert_eq!("PRIVMSG test :Testing!\r\n".parse(), Ok(message));
let message = Message { let message = Message {
prefix: Some(format!("test!test@test")), prefix: Some(format!("test!test@test")),
command: format!("PRIVMSG"), command: format!("PRIVMSG"),
args: vec![format!("test")], args: vec![format!("test")],
suffix: Some(format!("Still testing!")), suffix: Some(format!("Still testing!")),
}; };
assert_eq!(":test!test@test PRIVMSG test :Still testing!\r\n".parse(), Some(message)); assert_eq!(":test!test@test PRIVMSG test :Still testing!\r\n".parse(), Ok(message));
} }
#[test] #[test]

View file

@ -7,7 +7,7 @@ use client::data::message::Message;
/// List of all server responses as defined in [RFC 2812](http://tools.ietf.org/html/rfc2812). /// List of all server responses as defined in [RFC 2812](http://tools.ietf.org/html/rfc2812).
/// All commands are documented with their expected form from the RFC. /// All commands are documented with their expected form from the RFC.
#[derive(Copy, Show, PartialEq, FromPrimitive)] #[derive(Copy, Debug, PartialEq, FromPrimitive)]
#[repr(u16)] #[repr(u16)]
#[stable] #[stable]
pub enum Response { pub enum Response {
@ -435,7 +435,7 @@ impl Response {
/// Gets a response from a message. /// Gets a response from a message.
#[stable] #[stable]
pub fn from_message(m: &Message) -> Option<Response> { pub fn from_message(m: &Message) -> Option<Response> {
m.command.parse() m.command.parse().ok()
} }
/// Determines whether or not this response is an error response. /// Determines whether or not this response is an error response.
@ -446,11 +446,12 @@ impl Response {
} }
impl FromStr for Response { impl FromStr for Response {
fn from_str(s: &str) -> Option<Response> { type Err = &'static str;
if let Some(respcode) = s.parse() { fn from_str(s: &str) -> Result<Response, &'static str> {
FromPrimitive::from_u16(respcode) if let Ok(respcode) = s.parse() {
FromPrimitive::from_u16(respcode).ok_or("Failed to convert response code to u16.")
} else { } else {
None Err("Failed to parse response code.")
} }
} }
} }

View file

@ -7,7 +7,7 @@ use std::str::FromStr;
/// IRC User data. /// IRC User data.
#[stable] #[stable]
#[derive(Clone, Show)] #[derive(Clone, Debug)]
pub struct User { pub struct User {
/// The user's nickname. /// The user's nickname.
/// This is the only detail used in determining the equality of two users. /// This is the only detail used in determining the equality of two users.
@ -113,7 +113,7 @@ impl PartialEq for User {
/// The user's access level. /// The user's access level.
#[stable] #[stable]
#[derive(Copy, PartialEq, Clone, Show)] #[derive(Copy, PartialEq, Clone, Debug)]
pub enum AccessLevel { pub enum AccessLevel {
/// The channel owner (~). /// The channel owner (~).
#[stable] #[stable]
@ -174,15 +174,16 @@ impl PartialOrd for AccessLevel {
} }
impl FromStr for AccessLevel { impl FromStr for AccessLevel {
fn from_str(s: &str) -> Option<AccessLevel> { type Err = &'static str;
if s.len() == 0 { None } else { fn from_str(s: &str) -> Result<AccessLevel, &'static str> {
Some(match s.char_at(0) { if s.len() == 0 { Err("No access level in an empty string.") } else {
Ok(match s.char_at(0) {
'~' => AccessLevel::Owner, '~' => AccessLevel::Owner,
'&' => AccessLevel::Admin, '&' => AccessLevel::Admin,
'@' => AccessLevel::Oper, '@' => AccessLevel::Oper,
'%' => AccessLevel::HalfOp, '%' => AccessLevel::HalfOp,
'+' => AccessLevel::Voice, '+' => AccessLevel::Voice,
_ => return None, _ => return Err("Failed to parse access level."),
}) })
} }
} }
@ -206,7 +207,7 @@ impl<'a> Iterator for AccessLevelIterator<'a> {
if self.value.len() > 0 { if self.value.len() > 0 {
self.value = &self.value[1..]; self.value = &self.value[1..];
} }
ret ret.ok()
} }
} }
@ -217,13 +218,13 @@ mod test {
#[test] #[test]
fn parse_access_level() { fn parse_access_level() {
assert!("member".parse::<AccessLevel>().is_none()); assert!("member".parse::<AccessLevel>().is_err());
assert_eq!("~owner".parse::<AccessLevel>().unwrap(), Owner); assert_eq!("~owner".parse::<AccessLevel>().unwrap(), Owner);
assert_eq!("&admin".parse::<AccessLevel>().unwrap(), Admin); assert_eq!("&admin".parse::<AccessLevel>().unwrap(), Admin);
assert_eq!("@oper".parse::<AccessLevel>().unwrap(), Oper); assert_eq!("@oper".parse::<AccessLevel>().unwrap(), Oper);
assert_eq!("%halfop".parse::<AccessLevel>().unwrap(), HalfOp); assert_eq!("%halfop".parse::<AccessLevel>().unwrap(), HalfOp);
assert_eq!("+voice".parse::<AccessLevel>().unwrap(), Voice); assert_eq!("+voice".parse::<AccessLevel>().unwrap(), Voice);
assert!("".parse::<AccessLevel>().is_none()); assert!("".parse::<AccessLevel>().is_err());
} }
#[test] #[test]

View file

@ -280,14 +280,14 @@ impl<'a, T: IrcReader, U: IrcWriter> Iterator for ServerIterator<'a, T, U> {
fn next(&mut self) -> Option<IoResult<Message>> { fn next(&mut self) -> Option<IoResult<Message>> {
let res = self.get_next_line().and_then(|msg| let res = self.get_next_line().and_then(|msg|
match msg.parse() { match msg.parse() {
Some(msg) => { Ok(msg) => {
self.server.handle_message(&msg); self.server.handle_message(&msg);
Ok(msg) Ok(msg)
}, },
None => Err(IoError { Err(m) => Err(IoError {
kind: IoErrorKind::InvalidInput, kind: IoErrorKind::InvalidInput,
desc: "Failed to parse message.", desc: "Failed to parse message.",
detail: Some(msg) detail: Some(format!("{} (Message: {})", m, msg))
}) })
} }
); );