diff options
| author | Steven Fackler <sfackler@gmail.com> | 2019-02-08 20:42:34 +0100 |
|---|---|---|
| committer | Steven Fackler <sfackler@gmail.com> | 2019-02-13 19:40:17 -0800 |
| commit | 31bcec648aa57391115f877a2ca022d7ff6415aa (patch) | |
| tree | 2e9ba98a3146cb8eebf72d469a81615389edd4fd /src/libstd/io | |
| parent | 4772dc8087b1d0f2bab6d064fd930e596c82d439 (diff) | |
| download | rust-31bcec648aa57391115f877a2ca022d7ff6415aa.tar.gz rust-31bcec648aa57391115f877a2ca022d7ff6415aa.zip | |
Add vectored read and write support
This functionality has lived for a while in the tokio ecosystem, where it can improve performance by minimizing copies.
Diffstat (limited to 'src/libstd/io')
| -rw-r--r-- | src/libstd/io/buffered.rs | 33 | ||||
| -rw-r--r-- | src/libstd/io/cursor.rs | 217 | ||||
| -rw-r--r-- | src/libstd/io/impls.rs | 59 | ||||
| -rw-r--r-- | src/libstd/io/mod.rs | 124 | ||||
| -rw-r--r-- | src/libstd/io/util.rs | 18 |
5 files changed, 441 insertions, 10 deletions
diff --git a/src/libstd/io/buffered.rs b/src/libstd/io/buffered.rs index 0615cd59db4..a5edc4360ca 100644 --- a/src/libstd/io/buffered.rs +++ b/src/libstd/io/buffered.rs @@ -5,7 +5,7 @@ use io::prelude::*; use cmp; use error; use fmt; -use io::{self, Initializer, DEFAULT_BUF_SIZE, Error, ErrorKind, SeekFrom}; +use io::{self, Initializer, DEFAULT_BUF_SIZE, Error, ErrorKind, SeekFrom, IoVec, IoVecMut}; use memchr; /// The `BufReader` struct adds buffering to any reader. @@ -235,6 +235,19 @@ impl<R: Read> Read for BufReader<R> { Ok(nread) } + fn read_vectored(&mut self, bufs: &mut [IoVecMut<'_>]) -> io::Result<usize> { + let total_len = bufs.iter().map(|b| b.as_slice().len()).sum::<usize>(); + if self.pos == self.cap && total_len >= self.buf.len() { + return self.inner.read_vectored(bufs); + } + let nread = { + let mut rem = self.fill_buf()?; + rem.read_vectored(bufs)? + }; + self.consume(nread); + Ok(nread) + } + // we can't skip unconditionally because of the large buffer case in read. unsafe fn initializer(&self) -> Initializer { self.inner.initializer() @@ -577,9 +590,25 @@ impl<W: Write> Write for BufWriter<W> { self.panicked = false; r } else { - Write::write(&mut self.buf, buf) + self.buf.write(buf) + } + } + + fn write_vectored(&mut self, bufs: &[IoVec<'_>]) -> io::Result<usize> { + let total_len = bufs.iter().map(|b| b.as_slice().len()).sum::<usize>(); + if self.buf.len() + total_len > self.buf.capacity() { + self.flush_buf()?; + } + if total_len >= self.buf.capacity() { + self.panicked = true; + let r = self.inner.as_mut().unwrap().write_vectored(bufs); + self.panicked = false; + r + } else { + self.buf.write_vectored(bufs) } } + fn flush(&mut self) -> io::Result<()> { self.flush_buf().and_then(|()| self.get_mut().flush()) } diff --git a/src/libstd/io/cursor.rs b/src/libstd/io/cursor.rs index b205f788838..ef636cc6f8c 100644 --- a/src/libstd/io/cursor.rs +++ b/src/libstd/io/cursor.rs @@ -2,7 +2,7 @@ use io::prelude::*; use core::convert::TryInto; use cmp; -use io::{self, Initializer, SeekFrom, Error, ErrorKind}; +use io::{self, Initializer, SeekFrom, Error, ErrorKind, IoVec, IoVecMut}; /// A `Cursor` wraps an in-memory buffer and provides it with a /// [`Seek`] implementation. @@ -221,6 +221,19 @@ impl<T> Read for Cursor<T> where T: AsRef<[u8]> { Ok(n) } + fn read_vectored(&mut self, bufs: &mut [IoVecMut<'_>]) -> io::Result<usize> { + let mut nread = 0; + for buf in bufs { + let buf = buf.as_mut_slice(); + let n = self.read(buf)?; + nread += n; + if n < buf.len() { + break; + } + } + Ok(nread) + } + fn read_exact(&mut self, buf: &mut [u8]) -> io::Result<()> { let n = buf.len(); Read::read_exact(&mut self.fill_buf()?, buf)?; @@ -251,6 +264,24 @@ fn slice_write(pos_mut: &mut u64, slice: &mut [u8], buf: &[u8]) -> io::Result<us Ok(amt) } +fn slice_write_vectored( + pos_mut: &mut u64, + slice: &mut [u8], + bufs: &[IoVec<'_>], +) -> io::Result<usize> +{ + let mut nwritten = 0; + for buf in bufs { + let buf = buf.as_slice(); + let n = slice_write(pos_mut, slice, buf)?; + nwritten += n; + if n < buf.len() { + break; + } + } + Ok(nwritten) +} + // Resizing write implementation fn vec_write(pos_mut: &mut u64, vec: &mut Vec<u8>, buf: &[u8]) -> io::Result<usize> { let pos: usize = (*pos_mut).try_into().map_err(|_| { @@ -278,12 +309,31 @@ fn vec_write(pos_mut: &mut u64, vec: &mut Vec<u8>, buf: &[u8]) -> io::Result<usi Ok(buf.len()) } +fn vec_write_vectored( + pos_mut: &mut u64, + vec: &mut Vec<u8>, + bufs: &[IoVec<'_>], +) -> io::Result<usize> +{ + let mut nwritten = 0; + for buf in bufs { + nwritten += vec_write(pos_mut, vec, buf.as_slice())?; + } + Ok(nwritten) +} + #[stable(feature = "rust1", since = "1.0.0")] impl<'a> Write for Cursor<&'a mut [u8]> { #[inline] fn write(&mut self, buf: &[u8]) -> io::Result<usize> { slice_write(&mut self.pos, self.inner, buf) } + + #[inline] + fn write_vectored(&mut self, bufs: &[IoVec<'_>]) -> io::Result<usize> { + slice_write_vectored(&mut self.pos, self.inner, bufs) + } + fn flush(&mut self) -> io::Result<()> { Ok(()) } } @@ -292,6 +342,11 @@ impl<'a> Write for Cursor<&'a mut Vec<u8>> { fn write(&mut self, buf: &[u8]) -> io::Result<usize> { vec_write(&mut self.pos, self.inner, buf) } + + fn write_vectored(&mut self, bufs: &[IoVec<'_>]) -> io::Result<usize> { + vec_write_vectored(&mut self.pos, self.inner, bufs) + } + fn flush(&mut self) -> io::Result<()> { Ok(()) } } @@ -300,6 +355,11 @@ impl Write for Cursor<Vec<u8>> { fn write(&mut self, buf: &[u8]) -> io::Result<usize> { vec_write(&mut self.pos, &mut self.inner, buf) } + + fn write_vectored(&mut self, bufs: &[IoVec<'_>]) -> io::Result<usize> { + vec_write_vectored(&mut self.pos, &mut self.inner, bufs) + } + fn flush(&mut self) -> io::Result<()> { Ok(()) } } @@ -309,13 +369,19 @@ impl Write for Cursor<Box<[u8]>> { fn write(&mut self, buf: &[u8]) -> io::Result<usize> { slice_write(&mut self.pos, &mut self.inner, buf) } + + #[inline] + fn write_vectored(&mut self, bufs: &[IoVec<'_>]) -> io::Result<usize> { + slice_write_vectored(&mut self.pos, &mut self.inner, bufs) + } + fn flush(&mut self) -> io::Result<()> { Ok(()) } } #[cfg(test)] mod tests { use io::prelude::*; - use io::{Cursor, SeekFrom}; + use io::{Cursor, SeekFrom, IoVec, IoVecMut}; #[test] fn test_vec_writer() { @@ -323,7 +389,10 @@ mod tests { assert_eq!(writer.write(&[0]).unwrap(), 1); assert_eq!(writer.write(&[1, 2, 3]).unwrap(), 3); assert_eq!(writer.write(&[4, 5, 6, 7]).unwrap(), 4); - let b: &[_] = &[0, 1, 2, 3, 4, 5, 6, 7]; + assert_eq!(writer.write_vectored( + &[IoVec::new(&[]), IoVec::new(&[8, 9]), IoVec::new(&[10])], + ).unwrap(), 3); + let b: &[_] = &[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]; assert_eq!(writer, b); } @@ -333,7 +402,10 @@ mod tests { assert_eq!(writer.write(&[0]).unwrap(), 1); assert_eq!(writer.write(&[1, 2, 3]).unwrap(), 3); assert_eq!(writer.write(&[4, 5, 6, 7]).unwrap(), 4); - let b: &[_] = &[0, 1, 2, 3, 4, 5, 6, 7]; + assert_eq!(writer.write_vectored( + &[IoVec::new(&[]), IoVec::new(&[8, 9]), IoVec::new(&[10])], + ).unwrap(), 3); + let b: &[_] = &[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]; assert_eq!(&writer.get_ref()[..], b); } @@ -344,7 +416,10 @@ mod tests { assert_eq!(writer.write(&[0]).unwrap(), 1); assert_eq!(writer.write(&[1, 2, 3]).unwrap(), 3); assert_eq!(writer.write(&[4, 5, 6, 7]).unwrap(), 4); - let b: &[_] = &[0, 1, 2, 3, 4, 5, 6, 7]; + assert_eq!(writer.write_vectored( + &[IoVec::new(&[]), IoVec::new(&[8, 9]), IoVec::new(&[10])], + ).unwrap(), 3); + let b: &[_] = &[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]; assert_eq!(&writer.get_ref()[..], b); } @@ -367,6 +442,26 @@ mod tests { } #[test] + fn test_box_slice_writer_vectored() { + let mut writer = Cursor::new(vec![0u8; 9].into_boxed_slice()); + assert_eq!(writer.position(), 0); + assert_eq!(writer.write_vectored(&[IoVec::new(&[0])]).unwrap(), 1); + assert_eq!(writer.position(), 1); + assert_eq!( + writer.write_vectored(&[IoVec::new(&[1, 2, 3]), IoVec::new(&[4, 5, 6, 7])]).unwrap(), + 7, + ); + assert_eq!(writer.position(), 8); + assert_eq!(writer.write_vectored(&[]).unwrap(), 0); + assert_eq!(writer.position(), 8); + + assert_eq!(writer.write_vectored(&[IoVec::new(&[8, 9])]).unwrap(), 1); + assert_eq!(writer.write_vectored(&[IoVec::new(&[10])]).unwrap(), 0); + let b: &[_] = &[0, 1, 2, 3, 4, 5, 6, 7, 8]; + assert_eq!(&**writer.get_ref(), b); + } + + #[test] fn test_buf_writer() { let mut buf = [0 as u8; 9]; { @@ -388,6 +483,31 @@ mod tests { } #[test] + fn test_buf_writer_vectored() { + let mut buf = [0 as u8; 9]; + { + let mut writer = Cursor::new(&mut buf[..]); + assert_eq!(writer.position(), 0); + assert_eq!(writer.write_vectored(&[IoVec::new(&[0])]).unwrap(), 1); + assert_eq!(writer.position(), 1); + assert_eq!( + writer.write_vectored( + &[IoVec::new(&[1, 2, 3]), IoVec::new(&[4, 5, 6, 7])], + ).unwrap(), + 7, + ); + assert_eq!(writer.position(), 8); + assert_eq!(writer.write_vectored(&[]).unwrap(), 0); + assert_eq!(writer.position(), 8); + + assert_eq!(writer.write_vectored(&[IoVec::new(&[8, 9])]).unwrap(), 1); + assert_eq!(writer.write_vectored(&[IoVec::new(&[10])]).unwrap(), 0); + } + let b: &[_] = &[0, 1, 2, 3, 4, 5, 6, 7, 8]; + assert_eq!(buf, b); + } + + #[test] fn test_buf_writer_seek() { let mut buf = [0 as u8; 8]; { @@ -448,6 +568,35 @@ mod tests { } #[test] + fn test_mem_reader_vectored() { + let mut reader = Cursor::new(vec![0, 1, 2, 3, 4, 5, 6, 7]); + let mut buf = []; + assert_eq!(reader.read_vectored(&mut [IoVecMut::new(&mut buf)]).unwrap(), 0); + assert_eq!(reader.position(), 0); + let mut buf = [0]; + assert_eq!( + reader.read_vectored(&mut [IoVecMut::new(&mut []), IoVecMut::new(&mut buf)]).unwrap(), + 1, + ); + assert_eq!(reader.position(), 1); + let b: &[_] = &[0]; + assert_eq!(buf, b); + let mut buf1 = [0; 4]; + let mut buf2 = [0; 4]; + assert_eq!( + reader.read_vectored( + &mut [IoVecMut::new(&mut buf1), IoVecMut::new(&mut buf2)], + ).unwrap(), + 7, + ); + let b1: &[_] = &[1, 2, 3, 4]; + let b2: &[_] = &[5, 6, 7]; + assert_eq!(buf1, b1); + assert_eq!(&buf2[..3], b2); + assert_eq!(reader.read(&mut buf).unwrap(), 0); + } + + #[test] fn test_boxed_slice_reader() { let mut reader = Cursor::new(vec![0, 1, 2, 3, 4, 5, 6, 7].into_boxed_slice()); let mut buf = []; @@ -470,6 +619,35 @@ mod tests { } #[test] + fn test_boxed_slice_reader_vectored() { + let mut reader = Cursor::new(vec![0, 1, 2, 3, 4, 5, 6, 7].into_boxed_slice()); + let mut buf = []; + assert_eq!(reader.read_vectored(&mut [IoVecMut::new(&mut buf)]).unwrap(), 0); + assert_eq!(reader.position(), 0); + let mut buf = [0]; + assert_eq!( + reader.read_vectored(&mut [IoVecMut::new(&mut []), IoVecMut::new(&mut buf)]).unwrap(), + 1, + ); + assert_eq!(reader.position(), 1); + let b: &[_] = &[0]; + assert_eq!(buf, b); + let mut buf1 = [0; 4]; + let mut buf2 = [0; 4]; + assert_eq!( + reader.read_vectored( + &mut [IoVecMut::new(&mut buf1), IoVecMut::new(&mut buf2)], + ).unwrap(), + 7, + ); + let b1: &[_] = &[1, 2, 3, 4]; + let b2: &[_] = &[5, 6, 7]; + assert_eq!(buf1, b1); + assert_eq!(&buf2[..3], b2); + assert_eq!(reader.read(&mut buf).unwrap(), 0); + } + + #[test] fn read_to_end() { let mut reader = Cursor::new(vec![0, 1, 2, 3, 4, 5, 6, 7]); let mut v = Vec::new(); @@ -500,6 +678,35 @@ mod tests { } #[test] + fn test_slice_reader_vectored() { + let in_buf = vec![0, 1, 2, 3, 4, 5, 6, 7]; + let reader = &mut &in_buf[..]; + let mut buf = []; + assert_eq!(reader.read_vectored(&mut [IoVecMut::new(&mut buf)]).unwrap(), 0); + let mut buf = [0]; + assert_eq!( + reader.read_vectored(&mut [IoVecMut::new(&mut []), IoVecMut::new(&mut buf)]).unwrap(), + 1, + ); + assert_eq!(reader.len(), 7); + let b: &[_] = &[0]; + assert_eq!(buf, b); + let mut buf1 = [0; 4]; + let mut buf2 = [0; 4]; + assert_eq!( + reader.read_vectored( + &mut [IoVecMut::new(&mut buf1), IoVecMut::new(&mut buf2)], + ).unwrap(), + 7, + ); + let b1: &[_] = &[1, 2, 3, 4]; + let b2: &[_] = &[5, 6, 7]; + assert_eq!(buf1, b1); + assert_eq!(&buf2[..3], b2); + assert_eq!(reader.read(&mut buf).unwrap(), 0); + } + + #[test] fn test_read_exact() { let in_buf = vec![0, 1, 2, 3, 4, 5, 6, 7]; let reader = &mut &in_buf[..]; diff --git a/src/libstd/io/impls.rs b/src/libstd/io/impls.rs index ec75a87aec3..4bba4af77c4 100644 --- a/src/libstd/io/impls.rs +++ b/src/libstd/io/impls.rs @@ -1,5 +1,6 @@ use cmp; -use io::{self, SeekFrom, Read, Initializer, Write, Seek, BufRead, Error, ErrorKind}; +use io::{self, SeekFrom, Read, Initializer, Write, Seek, BufRead, Error, ErrorKind, IoVecMut, + IoVec}; use fmt; use mem; @@ -14,6 +15,11 @@ impl<'a, R: Read + ?Sized> Read for &'a mut R { } #[inline] + fn read_vectored(&mut self, bufs: &mut [IoVecMut<'_>]) -> io::Result<usize> { + (**self).read_vectored(bufs) + } + + #[inline] unsafe fn initializer(&self) -> Initializer { (**self).initializer() } @@ -39,6 +45,11 @@ impl<'a, W: Write + ?Sized> Write for &'a mut W { fn write(&mut self, buf: &[u8]) -> io::Result<usize> { (**self).write(buf) } #[inline] + fn write_vectored(&mut self, bufs: &[IoVec<'_>]) -> io::Result<usize> { + (**self).write_vectored(bufs) + } + + #[inline] fn flush(&mut self) -> io::Result<()> { (**self).flush() } #[inline] @@ -83,6 +94,11 @@ impl<R: Read + ?Sized> Read for Box<R> { } #[inline] + fn read_vectored(&mut self, bufs: &mut [IoVecMut<'_>]) -> io::Result<usize> { + (**self).read_vectored(bufs) + } + + #[inline] unsafe fn initializer(&self) -> Initializer { (**self).initializer() } @@ -108,6 +124,11 @@ impl<W: Write + ?Sized> Write for Box<W> { fn write(&mut self, buf: &[u8]) -> io::Result<usize> { (**self).write(buf) } #[inline] + fn write_vectored(&mut self, bufs: &[IoVec<'_>]) -> io::Result<usize> { + (**self).write_vectored(bufs) + } + + #[inline] fn flush(&mut self) -> io::Result<()> { (**self).flush() } #[inline] @@ -172,6 +193,19 @@ impl<'a> Read for &'a [u8] { } #[inline] + fn read_vectored(&mut self, bufs: &mut [IoVecMut<'_>]) -> io::Result<usize> { + let mut nread = 0; + for buf in bufs { + nread += self.read(buf.as_mut_slice())?; + if self.is_empty() { + break; + } + } + + Ok(nread) + } + + #[inline] unsafe fn initializer(&self) -> Initializer { Initializer::nop() } @@ -232,6 +266,19 @@ impl<'a> Write for &'a mut [u8] { } #[inline] + fn write_vectored(&mut self, bufs: &[IoVec<'_>]) -> io::Result<usize> { + let mut nwritten = 0; + for buf in bufs { + nwritten += self.write(buf.as_slice())?; + if self.is_empty() { + break; + } + } + + Ok(nwritten) + } + + #[inline] fn write_all(&mut self, data: &[u8]) -> io::Result<()> { if self.write(data)? == data.len() { Ok(()) @@ -255,6 +302,16 @@ impl Write for Vec<u8> { } #[inline] + fn write_vectored(&mut self, bufs: &[IoVec<'_>]) -> io::Result<usize> { + let len = bufs.iter().map(|b| b.as_slice().len()).sum(); + self.reserve(len); + for buf in bufs { + self.extend_from_slice(buf.as_slice()); + } + Ok(len) + } + + #[inline] fn write_all(&mut self, buf: &[u8]) -> io::Result<()> { self.extend_from_slice(buf); Ok(()) diff --git a/src/libstd/io/mod.rs b/src/libstd/io/mod.rs index c0570ae60a1..b9765605f8e 100644 --- a/src/libstd/io/mod.rs +++ b/src/libstd/io/mod.rs @@ -265,6 +265,7 @@ use slice; use str; use memchr; use ptr; +use sys; #[stable(feature = "rust1", since = "1.0.0")] pub use self::buffered::{BufReader, BufWriter, LineWriter}; @@ -520,6 +521,22 @@ pub trait Read { #[stable(feature = "rust1", since = "1.0.0")] fn read(&mut self, buf: &mut [u8]) -> Result<usize>; + /// Like `read`, except that it reads into a slice of buffers. + /// + /// Data is copied to fill each buffer in order, with the final buffer + /// written to possibly being only partially filled. This method must behave + /// as a single call to `read` with the buffers concatenated would. + /// + /// The default implementation simply passes the first nonempty buffer to + /// `read`. + #[unstable(feature = "iovec", issue = "0")] + fn read_vectored(&mut self, bufs: &mut [IoVecMut<'_>]) -> Result<usize> { + match bufs.iter_mut().map(|b| b.as_mut_slice()).find(|b| !b.is_empty()) { + Some(buf) => self.read(buf), + None => Ok(0), + } + } + /// Determines if this `Read`er can work with buffers of uninitialized /// memory. /// @@ -867,6 +884,85 @@ pub trait Read { } } +/// A buffer type used with `Read::read_vectored`. +/// +/// It is semantically a wrapper around an `&mut [u8]`, but is guaranteed to be +/// ABI compatible with the `iovec` type on Unix platforms and `WSABUF` on +/// Windows. +#[unstable(feature = "iovec", issue = "0")] +#[repr(transparent)] +pub struct IoVecMut<'a>(sys::io::IoVecMut<'a>); + +#[unstable(feature = "iovec", issue = "0")] +impl<'a> fmt::Debug for IoVecMut<'a> { + fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { + fmt::Debug::fmt(self.as_slice(), fmt) + } +} + +impl<'a> IoVecMut<'a> { + /// Creates a new `IoVecMut` wrapping a byte slice. + /// + /// # Panics + /// + /// Panics on Windows if the slice is larger than 4GB. + #[unstable(feature = "iovec", issue = "0")] + #[inline] + pub fn new(buf: &'a mut [u8]) -> IoVecMut<'a> { + IoVecMut(sys::io::IoVecMut::new(buf)) + } + + /// Returns a shared reference to the inner slice. + #[unstable(feature = "iovec", issue = "0")] + #[inline] + pub fn as_slice(&self) -> &'a [u8] { + self.0.as_slice() + } + + /// Returns a mutable reference to the inner slice. + #[unstable(feature = "iovec", issue = "0")] + #[inline] + pub fn as_mut_slice(&mut self) -> &'a mut [u8] { + self.0.as_mut_slice() + } +} + +/// A buffer type used with `Write::write_vectored`. +/// +/// It is semantically a wrapper around an `&[u8]`, but is guaranteed to be +/// ABI compatible with the `iovec` type on Unix platforms and `WSABUF` on +/// Windows. +#[unstable(feature = "iovec", issue = "0")] +#[repr(transparent)] +pub struct IoVec<'a>(sys::io::IoVec<'a>); + +#[unstable(feature = "iovec", issue = "0")] +impl<'a> fmt::Debug for IoVec<'a> { + fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { + fmt::Debug::fmt(self.as_slice(), fmt) + } +} + +impl<'a> IoVec<'a> { + /// Creates a new `IoVec` wrapping a byte slice. + /// + /// # Panics + /// + /// Panics on Windows if the slice is larger than 4GB. + #[unstable(feature = "iovec", issue = "0")] + #[inline] + pub fn new(buf: &'a [u8]) -> IoVec<'a> { + IoVec(sys::io::IoVec::new(buf)) + } + + /// Returns a shared reference to the inner slice. + #[unstable(feature = "iovec", issue = "0")] + #[inline] + pub fn as_slice(&self) -> &'a [u8] { + self.0.as_slice() + } +} + /// A type used to conditionally initialize buffers passed to `Read` methods. #[unstable(feature = "read_initializer", issue = "42788")] #[derive(Debug)] @@ -997,6 +1093,22 @@ pub trait Write { #[stable(feature = "rust1", since = "1.0.0")] fn write(&mut self, buf: &[u8]) -> Result<usize>; + /// Like `write`, except that it writes from a slice of buffers. + /// + /// Data is copied to from each buffer in order, with the final buffer + /// read from possibly being only partially consumed. This method must + /// behave as a call to `write` with the buffers concatenated would. + /// + /// The default implementation simply passes the first nonempty buffer to + /// `write`. + #[unstable(feature = "iovec", issue = "0")] + fn write_vectored(&mut self, bufs: &[IoVec<'_>]) -> Result<usize> { + match bufs.iter().map(|b| b.as_slice()).find(|b| !b.is_empty()) { + Some(buf) => self.write(buf), + None => Ok(0), + } + } + /// Flush this output stream, ensuring that all intermediately buffered /// contents reach their destination. /// @@ -1691,13 +1803,23 @@ impl<T: Read, U: Read> Read for Chain<T, U> { fn read(&mut self, buf: &mut [u8]) -> Result<usize> { if !self.done_first { match self.first.read(buf)? { - 0 if buf.len() != 0 => { self.done_first = true; } + 0 if buf.len() != 0 => self.done_first = true, n => return Ok(n), } } self.second.read(buf) } + fn read_vectored(&mut self, bufs: &mut [IoVecMut<'_>]) -> Result<usize> { + if !self.done_first { + match self.first.read_vectored(bufs)? { + 0 if bufs.iter().any(|b| !b.as_slice().is_empty()) => self.done_first = true, + n => return Ok(n), + } + } + self.second.read_vectored(bufs) + } + unsafe fn initializer(&self) -> Initializer { let initializer = self.first.initializer(); if initializer.should_initialize() { diff --git a/src/libstd/io/util.rs b/src/libstd/io/util.rs index 8df961a9add..6743018793f 100644 --- a/src/libstd/io/util.rs +++ b/src/libstd/io/util.rs @@ -1,7 +1,7 @@ #![allow(missing_copy_implementations)] use fmt; -use io::{self, Read, Initializer, Write, ErrorKind, BufRead}; +use io::{self, Read, Initializer, Write, ErrorKind, BufRead, IoVec, IoVecMut}; use mem; /// Copies the entire contents of a reader into a writer. @@ -153,6 +153,15 @@ impl Read for Repeat { } #[inline] + fn read_vectored(&mut self, bufs: &mut [IoVecMut<'_>]) -> io::Result<usize> { + let mut nwritten = 0; + for buf in bufs { + nwritten += self.read(buf.as_mut_slice())?; + } + Ok(nwritten) + } + + #[inline] unsafe fn initializer(&self) -> Initializer { Initializer::nop() } @@ -195,6 +204,13 @@ pub fn sink() -> Sink { Sink { _priv: () } } impl Write for Sink { #[inline] fn write(&mut self, buf: &[u8]) -> io::Result<usize> { Ok(buf.len()) } + + #[inline] + fn write_vectored(&mut self, bufs: &[IoVec<'_>]) -> io::Result<usize> { + let total_len = bufs.iter().map(|b| b.as_slice().len()).sum(); + Ok(total_len) + } + #[inline] fn flush(&mut self) -> io::Result<()> { Ok(()) } } |
