diff --git a/src/proto/irc.rs b/src/proto/irc.rs index 7b21599..040f15e 100644 --- a/src/proto/irc.rs +++ b/src/proto/irc.rs @@ -1 +1,79 @@ //! Implementation of IRC protocol for Tokio. + +use std::io; +use proto::line::LineCodec; +use proto::message::Message; +use tokio_core::io::{Codec, EasyBuf, Framed, Io}; +use tokio_proto::pipeline::{ServerProto, ClientProto}; + +/// An IRC codec built around an inner codec. +pub struct IrcCodec { + inner: C, +} + +impl IrcCodec { + /// Creates a new instance of IrcCodec wrapping a LineCodec with the specifiec encoding. + pub fn new(label: &str) -> io::Result> { + LineCodec::new(label).map(|codec| IrcCodec::from_codec(codec)) + } +} + +impl IrcCodec where C: Codec { + /// Creates a new instance of IrcCodec from the specified inner codec. + pub fn from_codec(codec: C) -> IrcCodec { + IrcCodec { inner: codec } + } +} + +impl Codec for IrcCodec where C: Codec { + type In = Message; + type Out = Message; + + fn decode(&mut self, buf: &mut EasyBuf) -> io::Result> { + self.inner.decode(buf).and_then(|res| res.map_or(Ok(None), |msg| { + msg.parse::().map(|msg| Some(msg)).map_err(|err| { + io::Error::new(io::ErrorKind::InvalidInput, err) + }) + })) + } + + fn encode(&mut self, msg: Message, buf: &mut Vec) -> io::Result<()> { + self.inner.encode(msg.to_string(), buf) + } +} + +/// Implementation of the IRC protocol backed by a line-delimited codec. +pub struct IrcProto { + encoding_label: String, +} + +impl IrcProto { + /// Creates a new IrcProto using the specified WHATWG encoding label. + fn new(label: &str) -> IrcProto { + IrcProto { encoding_label: label.to_owned() } + } +} + +impl ClientProto for IrcProto where T: Io + 'static { + type Request = Message; + type Response = Message; + + type Transport = Framed>; + type BindTransport = Result; + + fn bind_transport(&self, io: T) -> Self::BindTransport { + Ok(io.framed(try!(IrcCodec::new(&self.encoding_label)))) + } +} + +impl ServerProto for IrcProto where T: Io + 'static { + type Request = Message; + type Response = Message; + + type Transport = Framed>; + type BindTransport = Result; + + fn bind_transport(&self, io: T) -> Self::BindTransport { + Ok(io.framed(try!(IrcCodec::new(&self.encoding_label)))) + } +}