From e41c5fa768cd006fc35ae14d7f6dec7912462161 Mon Sep 17 00:00:00 2001 From: Jesse Luehrs Date: Mon, 8 Sep 2014 12:31:27 -0400 Subject: start moving things into callbacks --- examples/client.rs | 22 +++++++----- src/client.rs | 103 +++++++++++++++++++++++++++++------------------------ 2 files changed, 70 insertions(+), 55 deletions(-) diff --git a/examples/client.rs b/examples/client.rs index 6696460..4da1220 100644 --- a/examples/client.rs +++ b/examples/client.rs @@ -6,13 +6,17 @@ use irc::Client; use std::io; struct ExampleClient { + builder: irc::ClientBuilder, conn: io::BufferedStream, socket_name: Option, } impl irc::Client for ExampleClient { - fn new (conn: io::BufferedStream, socket_name: Option) -> ExampleClient { - ExampleClient { conn: conn, socket_name: socket_name } + fn new (builder: irc::ClientBuilder, conn: io::BufferedStream, socket_name: Option) -> ExampleClient { + ExampleClient { builder: builder, conn: conn, socket_name: socket_name } + } + fn builder (&self) -> &irc::ClientBuilder { + &self.builder } fn conn (&mut self) -> &mut io::BufferedStream { &mut self.conn @@ -23,12 +27,8 @@ impl irc::Client for ExampleClient { None => None, } } -} -fn main () { - let builder = irc::ClientBuilder::new("doytest", "chat.freenode.net"); - let client: ExampleClient = builder.connect(); - client.run_loop_with(|client, m| { + fn on_message (client: &mut ExampleClient, m: irc::Message) { print!("{}", m.to_protocol_string()); match *m.message_type() { Ping => { @@ -36,5 +36,11 @@ fn main () { }, _ => {}, } - }); + } +} + +fn main () { + let builder = irc::ClientBuilder::new("doytest", "chat.freenode.net"); + let client: ExampleClient = builder.connect(); + client.run_loop(); } diff --git a/src/client.rs b/src/client.rs index 55f2277..979d33b 100644 --- a/src/client.rs +++ b/src/client.rs @@ -56,56 +56,19 @@ impl ClientBuilder { } pub fn connect (self) -> T { - let nick = self.nick.clone(); - let pass = self.pass.clone(); - let hostname = self.hostname.clone(); - let username = self.username.clone(); - let servername = self.servername.clone(); - let realname = self.realname.clone(); - - let mut client = self.connect_raw(); - - let hostname = match hostname { - Some(host) => host, - None => { - match client.socket_name() { - Some(ref host) => host.to_string(), - // XXX something better here? - None => "localhost".to_string(), - } - }, - }; - - match pass { - Some(pass) => { - client.write(Message::new(None, Pass, vec![pass])); - }, - None => {}, - } - - client.write(Message::new(None, Nick, vec![nick])); - - client.write( - Message::new( - None, User, vec![ username, hostname, servername, realname ], - ) - ); - client - } - - pub fn connect_raw (self) -> T { let mut stream = io::TcpStream::connect(self.servername.as_slice(), self.port); let mut stream = stream.unwrap(); let socket_name = match stream.socket_name() { Ok(addr) => Some(addr.ip.to_string()), Err(_) => None, }; - Client::new(io::BufferedStream::new(stream), socket_name) + Client::new(self, io::BufferedStream::new(stream), socket_name) } } pub trait Client { - fn new (conn: io::BufferedStream, socket_name: Option) -> Self; + fn new (builder: ClientBuilder, conn: io::BufferedStream, socket_name: Option) -> Self; + fn builder (&self) -> &ClientBuilder; fn conn (&mut self) -> &mut io::BufferedStream; fn socket_name (&self) -> Option<&str>; @@ -123,16 +86,62 @@ pub trait Client { msg.write_protocol_string(self.conn()); } - // XXX eventually, we'll want to set up callbacks for specific events - // beforehand, and just have a `run_loop` method that loops and calls the - // preset callbacks as necessary. unfortunately, rust doesn't handle - // storing closures very well yet if they need to receive a borrowed - // pointer, and we would need to pass the client object into the callback - // in order to make this work - fn run_loop_with (mut self, handler: |&mut Self, Message|) { + fn run_loop_with (mut self, handler: |&mut Self, Message|) -> Self { loop { let m = self.read(); handler(&mut self, m); } + self + } + + // XXX once storing closures in structs works, we'll also want to provide + // a default CallbackClient impl of Client to allow users to not have to + // worry about the struct layout for simple cases. + fn run_loop (mut self) { + Client::on_connect(&mut self); + + let mut client = self.run_loop_with(|client, m| { + Client::on_message(client, m); + }); + + Client::on_disconnect(&mut client); + } + + fn on_connect (client: &mut Self) { + let nick = client.builder().nick.clone(); + let pass = client.builder().pass.clone(); + let username = client.builder().username.clone(); + let servername = client.builder().servername.clone(); + let realname = client.builder().realname.clone(); + + match pass { + Some(pass) => { + client.write(Message::new(None, Pass, vec![pass])); + }, + None => {}, + } + + client.write(Message::new(None, Nick, vec![nick])); + + let hostname = match client.builder().hostname { + Some(ref host) => host.clone(), + None => { + match client.socket_name() { + Some(ref host) => host.to_string(), + // XXX something better here? + None => "localhost".to_string(), + } + }, + }; + + client.write( + Message::new( + None, User, vec![ username, hostname, servername, realname ], + ) + ); } + + fn on_disconnect (client: &mut Self) { } + + fn on_message (client: &mut Self, m: Message) { } } -- cgit v1.2.3