Updated for Rust master.
This commit is contained in:
parent
3a85ad2708
commit
2f79f180d8
11 changed files with 47 additions and 48 deletions
|
@ -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;
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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."),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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.
|
||||||
|
|
|
@ -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]
|
||||||
|
|
|
@ -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.")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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]
|
||||||
|
|
|
@ -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))
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
Loading…
Reference in a new issue