diff --git a/src/io/mod.rs b/src/io/mod.rs index 72d89e10a..9f85217ee 100644 --- a/src/io/mod.rs +++ b/src/io/mod.rs @@ -14,6 +14,8 @@ use std::io; use futures::{BoxFuture, Async, Poll}; use futures::stream::BoxStream; +use mio::IoVec; + /// A convenience typedef around a `Future` whose error component is `io::Error` pub type IoFuture = BoxFuture; @@ -114,6 +116,57 @@ pub trait Io: io::Read + io::Write { Async::Ready(()) } + /// Read in a list of buffers all at once. + /// + /// This operation will attempt to read bytes from this socket and place + /// them into the list of buffers provided. Note that each buffer is an + /// `IoVec` which can be created from a byte slice. + /// + /// The buffers provided will be filled in sequentially. A buffer will be + /// entirely filled up before the next is written to. + /// + /// The number of bytes read is returned, if successful, or an error is + /// returned otherwise. If no bytes are available to be read yet then + /// a "would block" error is returned. This operation should not block. + /// + /// There is a default implementation for this function which treats this + /// as a single read using the first buffer in the list, but objects which + /// can implement this as an atomic read using all the buffers are + /// recommended to do so. For example, `TcpStream` can implement this + /// using the `readv` syscall. + fn read_vec(&mut self, bufs: &mut [&mut IoVec]) -> io::Result { + if bufs.is_empty() { + Ok(0) + } else { + self.read(bufs[0].as_mut_bytes()) + } + } + + /// Write a list of buffers all at once. + /// + /// This operation will attempt to write a list of byte buffers to this + /// socket. Note that each buffer is an `IoVec` which can be created from a + /// byte slice. + /// + /// The buffers provided will be written sequentially. A buffer will be + /// entirely written before the next is written. + /// + /// The number of bytes written is returned, if successful, or an error is + /// returned otherwise. If the socket is not currently writable then a + /// "would block" error is returned. This operation should not block. + /// + /// There is a default implementation for this function which writes the + /// first buffer only, but objects which can implement this as an atomic + /// write using all the buffers are recommended to do so. For example, + /// `TcpStream` can implement this using the `writev` syscall. + fn write_vec(&mut self, bufs: &[&IoVec]) -> io::Result { + if bufs.is_empty() { + Ok(0) + } else { + self.write(bufs[0].as_bytes()) + } + } + /// Provides a `Stream` and `Sink` interface for reading and writing to this /// `Io` object, using `Decode` and `Encode` to read and write the raw data. /// diff --git a/src/net/tcp.rs b/src/net/tcp.rs index 8ff84a557..192db9d6f 100644 --- a/src/net/tcp.rs +++ b/src/net/tcp.rs @@ -433,6 +433,38 @@ impl Io for TcpStream { fn poll_write(&mut self) -> Async<()> { ::poll_write(self) } + + fn read_vec(&mut self, bufs: &mut [&mut mio::IoVec]) -> io::Result { + if let Async::NotReady = self.poll_read() { + return Err(mio::would_block()) + } + let r = self.io.get_ref().read_bufs(bufs); + if is_wouldblock(&r) { + self.io.need_read(); + } + return r + + + } + + fn write_vec(&mut self, bufs: &[&mio::IoVec]) -> io::Result { + if let Async::NotReady = self.poll_write() { + return Err(mio::would_block()) + } + let r = self.io.get_ref().write_bufs(bufs); + if is_wouldblock(&r) { + self.io.need_write(); + } + return r + + } +} + +fn is_wouldblock(r: &io::Result) -> bool { + match *r { + Ok(_) => false, + Err(ref e) => e.kind() == io::ErrorKind::WouldBlock, + } } impl<'a> Read for &'a TcpStream {