Rollup merge of #74088 - tmiasko:write-all-vectored-empty, r=KodrAus

Avoid writes without any data in `Write::write_all_vectored`

Previously, when non-empty sequence of empty IoSlices have been provided
to `Write::write_all_vectored`, the buffers would be written as is with
`Write::write_vectored` and subsequently the return value `Ok(0)` would
be misinterpreted as an error.

Avoid writes without any data by advancing the buffers first. This
matches the documented behaviour of `Write::write_all_vectored`
and is analogous to what happens in `Write::write_all`.
This commit is contained in:
Yuki Okushi 2020-07-27 19:31:53 +09:00 committed by GitHub
commit 1361b02c9f
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23

View file

@ -251,7 +251,6 @@
use crate::cmp;
use crate::fmt;
use crate::mem;
use crate::memchr;
use crate::ops::{Deref, DerefMut};
use crate::ptr;
@ -1435,12 +1434,15 @@ pub trait Write {
/// ```
#[unstable(feature = "write_all_vectored", issue = "70436")]
fn write_all_vectored(&mut self, mut bufs: &mut [IoSlice<'_>]) -> Result<()> {
// Guarantee that bufs is empty if it contains no data,
// to avoid calling write_vectored if there is no data to be written.
bufs = IoSlice::advance(bufs, 0);
while !bufs.is_empty() {
match self.write_vectored(bufs) {
Ok(0) => {
return Err(Error::new(ErrorKind::WriteZero, "failed to write whole buffer"));
}
Ok(n) => bufs = IoSlice::advance(mem::take(&mut bufs), n),
Ok(n) => bufs = IoSlice::advance(bufs, n),
Err(ref e) if e.kind() == ErrorKind::Interrupted => {}
Err(e) => return Err(e),
}
@ -2958,6 +2960,7 @@ mod tests {
#[rustfmt::skip] // Becomes unreadable otherwise.
let tests: Vec<(_, &'static [u8])> = vec![
(vec![], &[]),
(vec![IoSlice::new(&[]), IoSlice::new(&[])], &[]),
(vec![IoSlice::new(&[1])], &[1]),
(vec![IoSlice::new(&[1, 2])], &[1, 2]),
(vec![IoSlice::new(&[1, 2, 3])], &[1, 2, 3]),