summaryrefslogtreecommitdiffstats
path: root/library/std/src/io
diff options
context:
space:
mode:
Diffstat (limited to 'library/std/src/io')
-rw-r--r--library/std/src/io/copy.rs81
-rw-r--r--library/std/src/io/copy/tests.rs38
-rw-r--r--library/std/src/io/readbuf.rs8
-rw-r--r--library/std/src/io/util.rs100
-rw-r--r--library/std/src/io/util/tests.rs13
5 files changed, 211 insertions, 29 deletions
diff --git a/library/std/src/io/copy.rs b/library/std/src/io/copy.rs
index ef1f4031e..3322940d2 100644
--- a/library/std/src/io/copy.rs
+++ b/library/std/src/io/copy.rs
@@ -1,4 +1,8 @@
use super::{BorrowedBuf, BufReader, BufWriter, ErrorKind, Read, Result, Write, DEFAULT_BUF_SIZE};
+use crate::alloc::Allocator;
+use crate::cmp;
+use crate::collections::VecDeque;
+use crate::io::IoSlice;
use crate::mem::MaybeUninit;
#[cfg(test)]
@@ -86,7 +90,7 @@ where
/// Specialization of the read-write loop that reuses the internal
/// buffer of a BufReader. If there's no buffer then the writer side
-/// should be used intead.
+/// should be used instead.
trait BufferedReaderSpec {
fn buffer_size(&self) -> usize;
@@ -104,7 +108,39 @@ where
}
default fn copy_to(&mut self, _to: &mut (impl Write + ?Sized)) -> Result<u64> {
- unimplemented!("only called from specializations");
+ unreachable!("only called from specializations")
+ }
+}
+
+impl BufferedReaderSpec for &[u8] {
+ fn buffer_size(&self) -> usize {
+ // prefer this specialization since the source "buffer" is all we'll ever need,
+ // even if it's small
+ usize::MAX
+ }
+
+ fn copy_to(&mut self, to: &mut (impl Write + ?Sized)) -> Result<u64> {
+ let len = self.len();
+ to.write_all(self)?;
+ *self = &self[len..];
+ Ok(len as u64)
+ }
+}
+
+impl<A: Allocator> BufferedReaderSpec for VecDeque<u8, A> {
+ fn buffer_size(&self) -> usize {
+ // prefer this specialization since the source "buffer" is all we'll ever need,
+ // even if it's small
+ usize::MAX
+ }
+
+ fn copy_to(&mut self, to: &mut (impl Write + ?Sized)) -> Result<u64> {
+ let len = self.len();
+ let (front, back) = self.as_slices();
+ let bufs = &mut [IoSlice::new(front), IoSlice::new(back)];
+ to.write_all_vectored(bufs)?;
+ self.clear();
+ Ok(len as u64)
}
}
@@ -218,6 +254,47 @@ impl<I: Write + ?Sized> BufferedWriterSpec for BufWriter<I> {
}
}
+impl<A: Allocator> BufferedWriterSpec for Vec<u8, A> {
+ fn buffer_size(&self) -> usize {
+ cmp::max(DEFAULT_BUF_SIZE, self.capacity() - self.len())
+ }
+
+ fn copy_from<R: Read + ?Sized>(&mut self, reader: &mut R) -> Result<u64> {
+ let mut bytes = 0;
+
+ // avoid allocating before we have determined that there's anything to read
+ if self.capacity() == 0 {
+ bytes = stack_buffer_copy(&mut reader.take(DEFAULT_BUF_SIZE as u64), self)?;
+ if bytes == 0 {
+ return Ok(0);
+ }
+ }
+
+ loop {
+ self.reserve(DEFAULT_BUF_SIZE);
+ let mut buf: BorrowedBuf<'_> = self.spare_capacity_mut().into();
+ match reader.read_buf(buf.unfilled()) {
+ Ok(()) => {}
+ Err(e) if e.kind() == ErrorKind::Interrupted => continue,
+ Err(e) => return Err(e),
+ };
+
+ let read = buf.filled().len();
+ if read == 0 {
+ break;
+ }
+
+ // SAFETY: BorrowedBuf guarantees all of its filled bytes are init
+ // and the number of read bytes can't exceed the spare capacity since
+ // that's what the buffer is borrowing from.
+ unsafe { self.set_len(self.len() + read) };
+ bytes += read as u64;
+ }
+
+ Ok(bytes)
+ }
+}
+
fn stack_buffer_copy<R: Read + ?Sized, W: Write + ?Sized>(
reader: &mut R,
writer: &mut W,
diff --git a/library/std/src/io/copy/tests.rs b/library/std/src/io/copy/tests.rs
index 8c816af15..af137eaf8 100644
--- a/library/std/src/io/copy/tests.rs
+++ b/library/std/src/io/copy/tests.rs
@@ -1,4 +1,6 @@
use crate::cmp::{max, min};
+use crate::collections::VecDeque;
+use crate::io;
use crate::io::*;
#[test]
@@ -19,7 +21,7 @@ struct ShortReader {
impl Read for ShortReader {
fn read(&mut self, buf: &mut [u8]) -> Result<usize> {
- let bytes = min(self.cap, self.read_size);
+ let bytes = min(self.cap, self.read_size).min(buf.len());
self.cap -= bytes;
self.observed_buffer = max(self.observed_buffer, buf.len());
Ok(bytes)
@@ -78,6 +80,40 @@ fn copy_specializes_bufreader() {
);
}
+#[test]
+fn copy_specializes_to_vec() {
+ let cap = 123456;
+ let mut source = ShortReader { cap, observed_buffer: 0, read_size: 1337 };
+ let mut sink = Vec::new();
+ assert_eq!(cap as u64, io::copy(&mut source, &mut sink).unwrap());
+ assert!(
+ source.observed_buffer > DEFAULT_BUF_SIZE,
+ "expected a large buffer to be provided to the reader"
+ );
+}
+
+#[test]
+fn copy_specializes_from_vecdeque() {
+ let mut source = VecDeque::with_capacity(100 * 1024);
+ for _ in 0..20 * 1024 {
+ source.push_front(0);
+ }
+ for _ in 0..20 * 1024 {
+ source.push_back(0);
+ }
+ let mut sink = WriteObserver { observed_buffer: 0 };
+ assert_eq!(40 * 1024u64, io::copy(&mut source, &mut sink).unwrap());
+ assert_eq!(20 * 1024, sink.observed_buffer);
+}
+
+#[test]
+fn copy_specializes_from_slice() {
+ let mut source = [1; 60 * 1024].as_slice();
+ let mut sink = WriteObserver { observed_buffer: 0 };
+ assert_eq!(60 * 1024u64, io::copy(&mut source, &mut sink).unwrap());
+ assert_eq!(60 * 1024, sink.observed_buffer);
+}
+
#[cfg(unix)]
mod io_benches {
use crate::fs::File;
diff --git a/library/std/src/io/readbuf.rs b/library/std/src/io/readbuf.rs
index 4800eeda0..034ddd8df 100644
--- a/library/std/src/io/readbuf.rs
+++ b/library/std/src/io/readbuf.rs
@@ -99,6 +99,13 @@ impl<'data> BorrowedBuf<'data> {
unsafe { MaybeUninit::slice_assume_init_ref(&self.buf[0..self.filled]) }
}
+ /// Returns a mutable reference to the filled portion of the buffer.
+ #[inline]
+ pub fn filled_mut(&mut self) -> &mut [u8] {
+ // SAFETY: We only slice the filled part of the buffer, which is always valid
+ unsafe { MaybeUninit::slice_assume_init_mut(&mut self.buf[0..self.filled]) }
+ }
+
/// Returns a cursor over the unfilled part of the buffer.
#[inline]
pub fn unfilled<'this>(&'this mut self) -> BorrowedCursor<'this> {
@@ -303,6 +310,7 @@ impl<'a> Write for BorrowedCursor<'a> {
Ok(buf.len())
}
+ #[inline]
fn flush(&mut self) -> Result<()> {
Ok(())
}
diff --git a/library/std/src/io/util.rs b/library/std/src/io/util.rs
index f076ee092..6bc8f181c 100644
--- a/library/std/src/io/util.rs
+++ b/library/std/src/io/util.rs
@@ -8,24 +8,41 @@ use crate::io::{
self, BorrowedCursor, BufRead, IoSlice, IoSliceMut, Read, Seek, SeekFrom, SizeHint, Write,
};
-/// A reader which is always at EOF.
+/// `Empty` ignores any data written via [`Write`], and will always be empty
+/// (returning zero bytes) when read via [`Read`].
///
-/// This struct is generally created by calling [`empty()`]. Please see
-/// the documentation of [`empty()`] for more details.
+/// This struct is generally created by calling [`empty()`]. Please
+/// see the documentation of [`empty()`] for more details.
#[stable(feature = "rust1", since = "1.0.0")]
#[non_exhaustive]
-#[derive(Copy, Clone, Default)]
+#[derive(Copy, Clone, Debug, Default)]
pub struct Empty;
-/// Constructs a new handle to an empty reader.
+/// Creates a value that is always at EOF for reads, and ignores all data written.
///
-/// All reads from the returned reader will return <code>[Ok]\(0)</code>.
+/// All calls to [`write`] on the returned instance will return [`Ok(buf.len())`]
+/// and the contents of the buffer will not be inspected.
+///
+/// All calls to [`read`] from the returned reader will return [`Ok(0)`].
+///
+/// [`Ok(buf.len())`]: Ok
+/// [`Ok(0)`]: Ok
+///
+/// [`write`]: Write::write
+/// [`read`]: Read::read
///
/// # Examples
///
-/// A slightly sad example of not reading anything into a buffer:
+/// ```rust
+/// use std::io::{self, Write};
///
+/// let buffer = vec![1, 2, 3, 5, 8];
+/// let num_bytes = io::empty().write(&buffer).unwrap();
+/// assert_eq!(num_bytes, 5);
/// ```
+///
+///
+/// ```rust
/// use std::io::{self, Read};
///
/// let mut buffer = String::new();
@@ -76,13 +93,6 @@ impl Seek for Empty {
}
}
-#[stable(feature = "std_debug", since = "1.16.0")]
-impl fmt::Debug for Empty {
- fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
- f.debug_struct("Empty").finish_non_exhaustive()
- }
-}
-
impl SizeHint for Empty {
#[inline]
fn upper_bound(&self) -> Option<usize> {
@@ -90,6 +100,54 @@ impl SizeHint for Empty {
}
}
+#[stable(feature = "empty_write", since = "1.73.0")]
+impl Write for Empty {
+ #[inline]
+ fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
+ Ok(buf.len())
+ }
+
+ #[inline]
+ fn write_vectored(&mut self, bufs: &[IoSlice<'_>]) -> io::Result<usize> {
+ let total_len = bufs.iter().map(|b| b.len()).sum();
+ Ok(total_len)
+ }
+
+ #[inline]
+ fn is_write_vectored(&self) -> bool {
+ true
+ }
+
+ #[inline]
+ fn flush(&mut self) -> io::Result<()> {
+ Ok(())
+ }
+}
+
+#[stable(feature = "empty_write", since = "1.73.0")]
+impl Write for &Empty {
+ #[inline]
+ fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
+ Ok(buf.len())
+ }
+
+ #[inline]
+ fn write_vectored(&mut self, bufs: &[IoSlice<'_>]) -> io::Result<usize> {
+ let total_len = bufs.iter().map(|b| b.len()).sum();
+ Ok(total_len)
+ }
+
+ #[inline]
+ fn is_write_vectored(&self) -> bool {
+ true
+ }
+
+ #[inline]
+ fn flush(&mut self) -> io::Result<()> {
+ Ok(())
+ }
+}
+
/// A reader which yields one byte over and over and over and over and over and...
///
/// This struct is generally created by calling [`repeat()`]. Please
@@ -182,19 +240,20 @@ impl fmt::Debug for Repeat {
/// A writer which will move data into the void.
///
-/// This struct is generally created by calling [`sink`]. Please
+/// This struct is generally created by calling [`sink()`]. Please
/// see the documentation of [`sink()`] for more details.
#[stable(feature = "rust1", since = "1.0.0")]
#[non_exhaustive]
-#[derive(Copy, Clone, Default)]
+#[derive(Copy, Clone, Debug, Default)]
pub struct Sink;
/// Creates an instance of a writer which will successfully consume all data.
///
-/// All calls to [`write`] on the returned instance will return `Ok(buf.len())`
+/// All calls to [`write`] on the returned instance will return [`Ok(buf.len())`]
/// and the contents of the buffer will not be inspected.
///
/// [`write`]: Write::write
+/// [`Ok(buf.len())`]: Ok
///
/// # Examples
///
@@ -259,10 +318,3 @@ impl Write for &Sink {
Ok(())
}
}
-
-#[stable(feature = "std_debug", since = "1.16.0")]
-impl fmt::Debug for Sink {
- fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
- f.debug_struct("Sink").finish_non_exhaustive()
- }
-}
diff --git a/library/std/src/io/util/tests.rs b/library/std/src/io/util/tests.rs
index 1baa94e64..6de91e29c 100644
--- a/library/std/src/io/util/tests.rs
+++ b/library/std/src/io/util/tests.rs
@@ -18,7 +18,7 @@ fn empty_reads() {
assert_eq!(e.read(&mut []).unwrap(), 0);
assert_eq!(e.read(&mut [0]).unwrap(), 0);
assert_eq!(e.read(&mut [0; 1024]).unwrap(), 0);
- assert_eq!(e.by_ref().read(&mut [0; 1024]).unwrap(), 0);
+ assert_eq!(Read::by_ref(&mut e).read(&mut [0; 1024]).unwrap(), 0);
let buf: &mut [MaybeUninit<_>] = &mut [];
let mut buf: BorrowedBuf<'_> = buf.into();
@@ -40,7 +40,7 @@ fn empty_reads() {
let buf: &mut [_] = &mut [MaybeUninit::uninit(); 1024];
let mut buf: BorrowedBuf<'_> = buf.into();
- e.by_ref().read_buf(buf.unfilled()).unwrap();
+ Read::by_ref(&mut e).read_buf(buf.unfilled()).unwrap();
assert_eq!(buf.len(), 0);
assert_eq!(buf.init_len(), 0);
}
@@ -66,6 +66,15 @@ fn empty_seeks() {
}
#[test]
+fn empty_sinks() {
+ let mut e = empty();
+ assert_eq!(e.write(&[]).unwrap(), 0);
+ assert_eq!(e.write(&[0]).unwrap(), 1);
+ assert_eq!(e.write(&[0; 1024]).unwrap(), 1024);
+ assert_eq!(Write::by_ref(&mut e).write(&[0; 1024]).unwrap(), 1024);
+}
+
+#[test]
fn repeat_repeats() {
let mut r = repeat(4);
let mut b = [0; 1024];