From a0003fd5b5d7749a746b46980fc83f190f912837 Mon Sep 17 00:00:00 2001 From: Jesse Luehrs Date: Wed, 3 Sep 2014 16:49:19 -0400 Subject: let's put message handling in its own module --- src/lib.rs | 2 +- src/message.rs | 155 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ src/types.rs | 155 --------------------------------------------------------- 3 files changed, 156 insertions(+), 156 deletions(-) create mode 100644 src/message.rs delete mode 100644 src/types.rs (limited to 'src') diff --git a/src/lib.rs b/src/lib.rs index ae7dc6f..d128db1 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -4,4 +4,4 @@ extern crate regex; mod constants; -mod types; +mod message; diff --git a/src/message.rs b/src/message.rs new file mode 100644 index 0000000..de5edeb --- /dev/null +++ b/src/message.rs @@ -0,0 +1,155 @@ +use constants::MessageType; + +#[deriving(PartialEq, Eq, Show)] +pub struct Message { + from: Option, + message_type: MessageType, + params: Vec, +} + +impl Message { + fn new (from: Option, message_type: MessageType, params: Vec) -> Message { + Message { from: from, message_type: message_type, params: params } + } + + pub fn parse (msg: &str) -> Result { + let message_parser = regex!(r"^(?::([^ ]+) )?([A-Z]+|[0-9]{3}) ([^\r\n\0]*)\r\n$"); + match message_parser.captures(msg) { + Some(captures) => { + let from = captures.at(1); + let from = if from.len() > 0 { Some(from.to_string()) } else { None }; + let command = captures.at(2); + + let params = Message::parse_params(captures.at(3)); + + match from_str(command) { + Some(c) => Ok(Message::new(from, c, params)), + None => Err("command parsing failed"), + } + }, + None => Err("message parsing failed"), + } + } + + pub fn from (&self) -> &Option { + &self.from + } + + pub fn message_type (&self) -> &MessageType { + &self.message_type + } + + pub fn params (&self) -> &Vec { + &self.params + } + + fn parse_params(params: &str) -> Vec { + let mut offset = 0; + let len = params.len(); + let mut ret = vec![]; + + loop { + if offset >= len { + return ret; + } + + if params.char_at(offset) == ':' { + ret.push(params.slice(offset + 1, len).to_string()); + return ret; + } + + let remaining = params.slice(offset, len); + match remaining.find(' ') { + Some(next) => { + ret.push(remaining.slice(0, next).to_string()); + offset = next + 1; + }, + None => { + ret.push(remaining.to_string()); + return ret; + } + } + } + } +} + +#[test] +fn test_message_parser () { + use constants::*; + + { + let msg = "PASS secretpasswordhere\r\n"; + assert_eq!( + Message::parse(msg), + Ok( + Message { + from: None, + message_type: CommandMessage(Pass), + params: vec!["secretpasswordhere".to_string()], + } + ) + ); + } + + { + let msg = ":WiZ NICK Kilroy\r\n"; + assert_eq!( + Message::parse(msg), + Ok( + Message { + from: Some("WiZ".to_string()), + message_type: CommandMessage(Nick), + params: vec!["Kilroy".to_string()], + } + ) + ); + } + + { + let msg = "QUIT :Gone to have lunch\r\n"; + assert_eq!( + Message::parse(msg), + Ok( + Message { + from: None, + message_type: CommandMessage(Quit), + params: vec!["Gone to have lunch".to_string()], + } + ) + ); + } + + { + let msg = ":Trillian SQUIT cm22.eng.umd.edu :Server out of control\r\n"; + assert_eq!( + Message::parse(msg), + Ok( + Message { + from: Some("Trillian".to_string()), + message_type: CommandMessage(Squit), + params: vec![ + "cm22.eng.umd.edu".to_string(), + "Server out of control".to_string(), + ], + } + ) + ); + } + + { + let msg = "401 doy :No such nick/channel\r\n"; + assert_eq!( + Message::parse(msg), + Ok( + Message { + from: None, + message_type: ReplyMessage(Reply(ERR_NOSUCHNICK)), + params: vec![ + "doy".to_string(), + "No such nick/channel".to_string(), + ], + } + ) + ); + } +} diff --git a/src/types.rs b/src/types.rs deleted file mode 100644 index de5edeb..0000000 --- a/src/types.rs +++ /dev/null @@ -1,155 +0,0 @@ -use constants::MessageType; - -#[deriving(PartialEq, Eq, Show)] -pub struct Message { - from: Option, - message_type: MessageType, - params: Vec, -} - -impl Message { - fn new (from: Option, message_type: MessageType, params: Vec) -> Message { - Message { from: from, message_type: message_type, params: params } - } - - pub fn parse (msg: &str) -> Result { - let message_parser = regex!(r"^(?::([^ ]+) )?([A-Z]+|[0-9]{3}) ([^\r\n\0]*)\r\n$"); - match message_parser.captures(msg) { - Some(captures) => { - let from = captures.at(1); - let from = if from.len() > 0 { Some(from.to_string()) } else { None }; - let command = captures.at(2); - - let params = Message::parse_params(captures.at(3)); - - match from_str(command) { - Some(c) => Ok(Message::new(from, c, params)), - None => Err("command parsing failed"), - } - }, - None => Err("message parsing failed"), - } - } - - pub fn from (&self) -> &Option { - &self.from - } - - pub fn message_type (&self) -> &MessageType { - &self.message_type - } - - pub fn params (&self) -> &Vec { - &self.params - } - - fn parse_params(params: &str) -> Vec { - let mut offset = 0; - let len = params.len(); - let mut ret = vec![]; - - loop { - if offset >= len { - return ret; - } - - if params.char_at(offset) == ':' { - ret.push(params.slice(offset + 1, len).to_string()); - return ret; - } - - let remaining = params.slice(offset, len); - match remaining.find(' ') { - Some(next) => { - ret.push(remaining.slice(0, next).to_string()); - offset = next + 1; - }, - None => { - ret.push(remaining.to_string()); - return ret; - } - } - } - } -} - -#[test] -fn test_message_parser () { - use constants::*; - - { - let msg = "PASS secretpasswordhere\r\n"; - assert_eq!( - Message::parse(msg), - Ok( - Message { - from: None, - message_type: CommandMessage(Pass), - params: vec!["secretpasswordhere".to_string()], - } - ) - ); - } - - { - let msg = ":WiZ NICK Kilroy\r\n"; - assert_eq!( - Message::parse(msg), - Ok( - Message { - from: Some("WiZ".to_string()), - message_type: CommandMessage(Nick), - params: vec!["Kilroy".to_string()], - } - ) - ); - } - - { - let msg = "QUIT :Gone to have lunch\r\n"; - assert_eq!( - Message::parse(msg), - Ok( - Message { - from: None, - message_type: CommandMessage(Quit), - params: vec!["Gone to have lunch".to_string()], - } - ) - ); - } - - { - let msg = ":Trillian SQUIT cm22.eng.umd.edu :Server out of control\r\n"; - assert_eq!( - Message::parse(msg), - Ok( - Message { - from: Some("Trillian".to_string()), - message_type: CommandMessage(Squit), - params: vec![ - "cm22.eng.umd.edu".to_string(), - "Server out of control".to_string(), - ], - } - ) - ); - } - - { - let msg = "401 doy :No such nick/channel\r\n"; - assert_eq!( - Message::parse(msg), - Ok( - Message { - from: None, - message_type: ReplyMessage(Reply(ERR_NOSUCHNICK)), - params: vec![ - "doy".to_string(), - "No such nick/channel".to_string(), - ], - } - ) - ); - } -} -- cgit v1.2.3