add read_bufs and write_bufs to Io and TcpStream

This commit is contained in:
Sean McArthur 2017-01-24 12:27:11 -08:00
parent a4b4d57cb7
commit 829563ccfc
2 changed files with 85 additions and 0 deletions

View File

@ -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<T> = BoxFuture<T, io::Error>;
@ -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<usize> {
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<usize> {
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.
///

View File

@ -433,6 +433,38 @@ impl Io for TcpStream {
fn poll_write(&mut self) -> Async<()> {
<TcpStream>::poll_write(self)
}
fn read_vec(&mut self, bufs: &mut [&mut mio::IoVec]) -> io::Result<usize> {
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<usize> {
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<T>(r: &io::Result<T>) -> bool {
match *r {
Ok(_) => false,
Err(ref e) => e.kind() == io::ErrorKind::WouldBlock,
}
}
impl<'a> Read for &'a TcpStream {