|
261 | 261 |
|
262 | 262 | use crate::cmp;
|
263 | 263 | use crate::fmt;
|
| 264 | +use crate::mem; |
264 | 265 | use crate::memchr;
|
265 | 266 | use crate::ops::{Deref, DerefMut};
|
266 | 267 | use crate::ptr;
|
@@ -1376,6 +1377,67 @@ pub trait Write {
|
1376 | 1377 | Ok(())
|
1377 | 1378 | }
|
1378 | 1379 |
|
| 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 | + |
1379 | 1441 | /// Writes a formatted string into this writer, returning any error
|
1380 | 1442 | /// encountered.
|
1381 | 1443 | ///
|
@@ -2423,7 +2485,7 @@ impl<B: BufRead> Iterator for Lines<B> {
|
2423 | 2485 | #[cfg(test)]
|
2424 | 2486 | mod tests {
|
2425 | 2487 | use super::{repeat, Cursor, SeekFrom};
|
2426 |
| - use crate::cmp; |
| 2488 | + use crate::cmp::{self, min}; |
2427 | 2489 | use crate::io::prelude::*;
|
2428 | 2490 | use crate::io::{self, IoSlice, IoSliceMut};
|
2429 | 2491 | use crate::ops::Deref;
|
@@ -2812,4 +2874,102 @@ mod tests {
|
2812 | 2874 | bufs = IoSlice::advance(bufs, 9);
|
2813 | 2875 | assert!(bufs.is_empty());
|
2814 | 2876 | }
|
| 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 | + } |
2815 | 2975 | }
|
0 commit comments