#![feature(slicing_syntax)] use std::borrow::ToOwned; #[derive(Clone)] pub struct Message { pub prefix: Option, pub command: String, pub content: Vec, pub suffix: Option } impl Message { pub fn new(prefix: Option, command: String, content: Vec, suffix: Option) -> Message { Message { prefix: prefix, command: command, content: content, suffix: suffix } } pub fn parse(i: &str) -> Option { let len = i.len(); let mut s = i; let prefix = if len >= 1 && s.char_at(0) == ':' { s.find(' ').map(|i| { let p = s.slice_chars(1, i).to_owned(); s = &s[i..]; p }) } else { None }; let command = s.find(' ').map(|i| { let p = s.slice_chars(0, i).to_owned(); s = &s[i..]; p }).and_then(|c| c.parse()); let mut content = Vec::with_capacity(15); let mut suffix = None; while s.len() > 0 { if s.char_at(0) == ':' { suffix = Some(s.slice_from(1).to_owned()); break } s.find(' ').map(|i| { content.push(s.slice_chars(0, i).to_owned()); s = &s[i..]; }); } command.map(move |c| Message::new(prefix, c, content, suffix)) } pub fn format(&self) -> String { let mut s = String::with_capacity(512); if let Some(ref p) = self.prefix { s.push(':'); s.push_str(&p[]); s.push(' '); } s.push_str(&self.command.to_string()[]); s.push(' '); if let Some(ref p) = self.suffix { s.push(':'); s.push_str(&p[]); } s } } trait Command { fn name() -> String; fn to_message(&self) -> Message; fn from_message(msg: &Message) -> Option; } macro_rules! command ( ($name: ident { $($field: ident: $t: ty),* } to $to_msg: expr; from $from_msg: expr;) => ( pub struct $name { $($field: $t),* } impl Command for $name { fn name() -> String { stringify!($name).to_owned() } fn to_message(&self) -> Message { ($to_msg)(self) } fn from_message(msg: &Message) -> Option<$name> { ($from_msg)(msg) } } ) ); command!(Pass { password: String } to |&:s: &Pass| Message::new(None, "PASS".to_owned(), Vec::new(), Some(s.password.clone())); from |&:msg: &Message| msg.clone().suffix.map(|s| Pass { password: s });); /*command!(Ping { server1: Option, server2: Option } to |s| { let m = Message::new(); if let Some(s) = s.server1 { m.content.push(s) } if let Some(s) = s.server2 { m.content.push(s) } m } from |msg| Ping { server2: msg.content.pop(), server1: msg.content.pop() } ); */ fn main() { let pass: Option = Message::parse("PASS :meep").and_then(|m| Command::from_message(&m)); println!("{}", pass.unwrap().to_message().format()); }