Skip to content

Commit 33a4999

Browse files
committed
Add io::Write::write_all_vectored
Similar to io::Write::write_all but uses io::Write::write_vectored instead.
1 parent 2113659 commit 33a4999

File tree

1 file changed

+161
-1
lines changed

1 file changed

+161
-1
lines changed

src/libstd/io/mod.rs

Lines changed: 161 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -261,6 +261,7 @@
261261

262262
use crate::cmp;
263263
use crate::fmt;
264+
use crate::mem;
264265
use crate::memchr;
265266
use crate::ops::{Deref, DerefMut};
266267
use crate::ptr;
@@ -1376,6 +1377,67 @@ pub trait Write {
13761377
Ok(())
13771378
}
13781379

1380+
/// Attempts to write an multiple buffers into this writer.
1381+
///
1382+
/// This method will continuously call [`write_vectored`] until there is no
1383+
/// more data to be written or an error of non-[`ErrorKind::Interrupted`]
1384+
/// kind is returned. This method will not return until all buffers have
1385+
/// been successfully written or such an error occurs. The first error that
1386+
/// is not of [`ErrorKind::Interrupted`] kind generated from this method
1387+
/// will be returned.
1388+
///
1389+
/// If the buffer contains no data, this will never call [`write_vectored`].
1390+
///
1391+
/// # Notes
1392+
///
1393+
/// Different to `io::Write::write_vectored` this takes a *mutable*
1394+
/// reference to a slice of `IoSlice`s, not a non-mutable reference, because
1395+
/// we need to modify the slice to keep track of the bytes already written.
1396+
///
1397+
/// Once this function returns the contents of `bufs` is undefined, not
1398+
/// undefined as in memory unsafe but we don't know what the contents of
1399+
/// `bufs` will be as that depends on how many writes we needed to do. We
1400+
/// advice to see this function as taking ownership of `bufs` and don't use
1401+
/// the variable after the future returns. The underlying buffers, to which
1402+
/// `IoSlice` points (not the `IoSlice` itself), are unchanged and can be
1403+
/// reused.
1404+
///
1405+
/// # Examples
1406+
///
1407+
/// ```
1408+
/// #![feature(write_all_vectored)]
1409+
/// # fn main() -> std::io::Result<()> {
1410+
///
1411+
/// use std::io::{Write, IoSlice};
1412+
///
1413+
/// let mut writer = Vec::new();
1414+
/// let bufs = &mut [
1415+
/// IoSlice::new(&[1]),
1416+
/// IoSlice::new(&[2, 3]),
1417+
/// IoSlice::new(&[4, 5, 6]),
1418+
/// ];
1419+
///
1420+
/// writer.write_all_vectored(bufs)?;
1421+
/// // Note: the contents of `bufs` is now undefined, see the Notes section.
1422+
///
1423+
/// assert_eq!(writer, &[1, 2, 3, 4, 5, 6]);
1424+
/// # Ok(()) }
1425+
/// ```
1426+
#[unstable(feature = "write_all_vectored", issue = "70436")]
1427+
fn write_all_vectored(&mut self, mut bufs: &mut [IoSlice<'_>]) -> Result<()> {
1428+
while !bufs.is_empty() {
1429+
match self.write_vectored(bufs) {
1430+
Ok(0) => {
1431+
return Err(Error::new(ErrorKind::WriteZero, "failed to write whole buffer"));
1432+
}
1433+
Ok(n) => bufs = IoSlice::advance(mem::replace(&mut bufs, &mut []), n),
1434+
Err(ref e) if e.kind() == ErrorKind::Interrupted => {}
1435+
Err(e) => return Err(e),
1436+
}
1437+
}
1438+
Ok(())
1439+
}
1440+
13791441
/// Writes a formatted string into this writer, returning any error
13801442
/// encountered.
13811443
///
@@ -2423,7 +2485,7 @@ impl<B: BufRead> Iterator for Lines<B> {
24232485
#[cfg(test)]
24242486
mod tests {
24252487
use super::{repeat, Cursor, SeekFrom};
2426-
use crate::cmp;
2488+
use crate::cmp::{self, min};
24272489
use crate::io::prelude::*;
24282490
use crate::io::{self, IoSlice, IoSliceMut};
24292491
use crate::ops::Deref;
@@ -2812,4 +2874,102 @@ mod tests {
28122874
bufs = IoSlice::advance(bufs, 9);
28132875
assert!(bufs.is_empty());
28142876
}
2877+
2878+
/// Create a new writer that reads from at most `n_bufs` and reads
2879+
/// `per_call` bytes (in total) per call to write.
2880+
fn test_writer(n_bufs: usize, per_call: usize) -> TestWriter {
2881+
TestWriter { n_bufs, per_call, written: Vec::new() }
2882+
}
2883+
2884+
struct TestWriter {
2885+
n_bufs: usize,
2886+
per_call: usize,
2887+
written: Vec<u8>,
2888+
}
2889+
2890+
impl Write for TestWriter {
2891+
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
2892+
self.write_vectored(&[IoSlice::new(buf)])
2893+
}
2894+
2895+
fn write_vectored(&mut self, bufs: &[IoSlice<'_>]) -> io::Result<usize> {
2896+
let mut left = self.per_call;
2897+
let mut written = 0;
2898+
for buf in bufs.iter().take(self.n_bufs) {
2899+
let n = min(left, buf.len());
2900+
self.written.extend_from_slice(&buf[0..n]);
2901+
left -= n;
2902+
written += n;
2903+
}
2904+
Ok(written)
2905+
}
2906+
2907+
fn flush(&mut self) -> io::Result<()> {
2908+
Ok(())
2909+
}
2910+
}
2911+
2912+
#[test]
2913+
fn test_writer_read_from_one_buf() {
2914+
let mut writer = test_writer(1, 2);
2915+
2916+
assert_eq!(writer.write(&[]).unwrap(), 0);
2917+
assert_eq!(writer.write_vectored(&[]).unwrap(), 0);
2918+
2919+
// Read at most 2 bytes.
2920+
assert_eq!(writer.write(&[1, 1, 1]).unwrap(), 2);
2921+
let bufs = &[IoSlice::new(&[2, 2, 2])];
2922+
assert_eq!(writer.write_vectored(bufs).unwrap(), 2);
2923+
2924+
// Only read from first buf.
2925+
let bufs = &[IoSlice::new(&[3]), IoSlice::new(&[4, 4])];
2926+
assert_eq!(writer.write_vectored(bufs).unwrap(), 1);
2927+
2928+
assert_eq!(writer.written, &[1, 1, 2, 2, 3]);
2929+
}
2930+
2931+
#[test]
2932+
fn test_writer_read_from_multiple_bufs() {
2933+
let mut writer = test_writer(3, 3);
2934+
2935+
// Read at most 3 bytes from two buffers.
2936+
let bufs = &[IoSlice::new(&[1]), IoSlice::new(&[2, 2, 2])];
2937+
assert_eq!(writer.write_vectored(bufs).unwrap(), 3);
2938+
2939+
// Read at most 3 bytes from three buffers.
2940+
let bufs = &[IoSlice::new(&[3]), IoSlice::new(&[4]), IoSlice::new(&[5, 5])];
2941+
assert_eq!(writer.write_vectored(bufs).unwrap(), 3);
2942+
2943+
assert_eq!(writer.written, &[1, 2, 2, 3, 4, 5]);
2944+
}
2945+
2946+
#[test]
2947+
fn test_write_all_vectored() {
2948+
#[rustfmt::skip] // Becomes unreadable otherwise.
2949+
let tests: Vec<(_, &'static [u8])> = vec![
2950+
(vec![], &[]),
2951+
(vec![IoSlice::new(&[1])], &[1]),
2952+
(vec![IoSlice::new(&[1, 2])], &[1, 2]),
2953+
(vec![IoSlice::new(&[1, 2, 3])], &[1, 2, 3]),
2954+
(vec![IoSlice::new(&[1, 2, 3, 4])], &[1, 2, 3, 4]),
2955+
(vec![IoSlice::new(&[1, 2, 3, 4, 5])], &[1, 2, 3, 4, 5]),
2956+
(vec![IoSlice::new(&[1]), IoSlice::new(&[2])], &[1, 2]),
2957+
(vec![IoSlice::new(&[1, 1]), IoSlice::new(&[2, 2])], &[1, 1, 2, 2]),
2958+
(vec![IoSlice::new(&[1, 1, 1]), IoSlice::new(&[2, 2, 2])], &[1, 1, 1, 2, 2, 2]),
2959+
(vec![IoSlice::new(&[1, 1, 1, 1]), IoSlice::new(&[2, 2, 2, 2])], &[1, 1, 1, 1, 2, 2, 2, 2]),
2960+
(vec![IoSlice::new(&[1]), IoSlice::new(&[2]), IoSlice::new(&[3])], &[1, 2, 3]),
2961+
(vec![IoSlice::new(&[1, 1]), IoSlice::new(&[2, 2]), IoSlice::new(&[3, 3])], &[1, 1, 2, 2, 3, 3]),
2962+
(vec![IoSlice::new(&[1, 1, 1]), IoSlice::new(&[2, 2, 2]), IoSlice::new(&[3, 3, 3])], &[1, 1, 1, 2, 2, 2, 3, 3, 3]),
2963+
];
2964+
2965+
let writer_configs = &[(1, 1), (1, 2), (1, 3), (2, 2), (2, 3), (3, 3)];
2966+
2967+
for (n_bufs, per_call) in writer_configs.iter().copied() {
2968+
for (mut input, wanted) in tests.clone().into_iter() {
2969+
let mut writer = test_writer(n_bufs, per_call);
2970+
assert!(writer.write_all_vectored(&mut *input).is_ok());
2971+
assert_eq!(&*writer.written, &*wanted);
2972+
}
2973+
}
2974+
}
28152975
}

0 commit comments

Comments
 (0)