summaryrefslogtreecommitdiffstats
path: root/library/std/src/io
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-17 12:06:37 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-17 12:06:37 +0000
commit246f239d9f40f633160f0c18f87a20922d4e77bb (patch)
tree5a88572663584b3d4d28e5a20e10abab1be40884 /library/std/src/io
parentReleasing progress-linux version 1.64.0+dfsg1-1~progress7.99u1. (diff)
downloadrustc-246f239d9f40f633160f0c18f87a20922d4e77bb.tar.xz
rustc-246f239d9f40f633160f0c18f87a20922d4e77bb.zip
Merging debian version 1.65.0+dfsg1-2.
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to '')
-rw-r--r--library/std/src/io/buffered/bufreader.rs22
-rw-r--r--library/std/src/io/buffered/bufreader/buffer.rs27
-rw-r--r--library/std/src/io/buffered/tests.rs58
-rw-r--r--library/std/src/io/copy.rs34
-rw-r--r--library/std/src/io/cursor.rs10
-rw-r--r--library/std/src/io/error.rs11
-rw-r--r--library/std/src/io/error/repr_bitpacked.rs4
-rw-r--r--library/std/src/io/impls.rs22
-rw-r--r--library/std/src/io/mod.rs93
-rw-r--r--library/std/src/io/readbuf.rs307
-rw-r--r--library/std/src/io/readbuf/tests.rs220
-rw-r--r--library/std/src/io/stdio.rs51
-rw-r--r--library/std/src/io/tests.rs23
-rw-r--r--library/std/src/io/util.rs14
-rw-r--r--library/std/src/io/util/tests.rs48
15 files changed, 533 insertions, 411 deletions
diff --git a/library/std/src/io/buffered/bufreader.rs b/library/std/src/io/buffered/bufreader.rs
index f7fbaa9c2..4f339a18a 100644
--- a/library/std/src/io/buffered/bufreader.rs
+++ b/library/std/src/io/buffered/bufreader.rs
@@ -2,7 +2,7 @@ mod buffer;
use crate::fmt;
use crate::io::{
- self, BufRead, IoSliceMut, Read, ReadBuf, Seek, SeekFrom, SizeHint, DEFAULT_BUF_SIZE,
+ self, BorrowedCursor, BufRead, IoSliceMut, Read, Seek, SeekFrom, SizeHint, DEFAULT_BUF_SIZE,
};
use buffer::Buffer;
@@ -224,6 +224,14 @@ impl<R> BufReader<R> {
}
}
+// This is only used by a test which asserts that the initialization-tracking is correct.
+#[cfg(test)]
+impl<R> BufReader<R> {
+ pub fn initialized(&self) -> usize {
+ self.buf.initialized()
+ }
+}
+
impl<R: Seek> BufReader<R> {
/// Seeks relative to the current position. If the new position lies within the buffer,
/// the buffer will not be flushed, allowing for more efficient seeks.
@@ -266,21 +274,21 @@ impl<R: Read> Read for BufReader<R> {
Ok(nread)
}
- fn read_buf(&mut self, buf: &mut ReadBuf<'_>) -> io::Result<()> {
+ fn read_buf(&mut self, mut cursor: BorrowedCursor<'_>) -> io::Result<()> {
// If we don't have any buffered data and we're doing a massive read
// (larger than our internal buffer), bypass our internal buffer
// entirely.
- if self.buf.pos() == self.buf.filled() && buf.remaining() >= self.capacity() {
+ if self.buf.pos() == self.buf.filled() && cursor.capacity() >= self.capacity() {
self.discard_buffer();
- return self.inner.read_buf(buf);
+ return self.inner.read_buf(cursor);
}
- let prev = buf.filled_len();
+ let prev = cursor.written();
let mut rem = self.fill_buf()?;
- rem.read_buf(buf)?;
+ rem.read_buf(cursor.reborrow())?;
- self.consume(buf.filled_len() - prev); //slice impl of read_buf known to never unfill buf
+ self.consume(cursor.written() - prev); //slice impl of read_buf known to never unfill buf
Ok(())
}
diff --git a/library/std/src/io/buffered/bufreader/buffer.rs b/library/std/src/io/buffered/bufreader/buffer.rs
index 8ae01f3b0..e9e29d60c 100644
--- a/library/std/src/io/buffered/bufreader/buffer.rs
+++ b/library/std/src/io/buffered/bufreader/buffer.rs
@@ -9,7 +9,7 @@
/// that user code which wants to do reads from a `BufReader` via `buffer` + `consume` can do so
/// without encountering any runtime bounds checks.
use crate::cmp;
-use crate::io::{self, Read, ReadBuf};
+use crate::io::{self, BorrowedBuf, Read};
use crate::mem::MaybeUninit;
pub struct Buffer {
@@ -20,13 +20,19 @@ pub struct Buffer {
// Each call to `fill_buf` sets `filled` to indicate how many bytes at the start of `buf` are
// initialized with bytes from a read.
filled: usize,
+ // This is the max number of bytes returned across all `fill_buf` calls. We track this so that we
+ // can accurately tell `read_buf` how many bytes of buf are initialized, to bypass as much of its
+ // defensive initialization as possible. Note that while this often the same as `filled`, it
+ // doesn't need to be. Calls to `fill_buf` are not required to actually fill the buffer, and
+ // omitting this is a huge perf regression for `Read` impls that do not.
+ initialized: usize,
}
impl Buffer {
#[inline]
pub fn with_capacity(capacity: usize) -> Self {
let buf = Box::new_uninit_slice(capacity);
- Self { buf, pos: 0, filled: 0 }
+ Self { buf, pos: 0, filled: 0, initialized: 0 }
}
#[inline]
@@ -51,6 +57,12 @@ impl Buffer {
self.pos
}
+ // This is only used by a test which asserts that the initialization-tracking is correct.
+ #[cfg(test)]
+ pub fn initialized(&self) -> usize {
+ self.initialized
+ }
+
#[inline]
pub fn discard_buffer(&mut self) {
self.pos = 0;
@@ -93,12 +105,17 @@ impl Buffer {
if self.pos >= self.filled {
debug_assert!(self.pos == self.filled);
- let mut readbuf = ReadBuf::uninit(&mut self.buf);
+ let mut buf = BorrowedBuf::from(&mut *self.buf);
+ // SAFETY: `self.filled` bytes will always have been initialized.
+ unsafe {
+ buf.set_init(self.initialized);
+ }
- reader.read_buf(&mut readbuf)?;
+ reader.read_buf(buf.unfilled())?;
- self.filled = readbuf.filled_len();
self.pos = 0;
+ self.filled = buf.len();
+ self.initialized = buf.init_len();
}
Ok(self.buffer())
}
diff --git a/library/std/src/io/buffered/tests.rs b/library/std/src/io/buffered/tests.rs
index fe45b1326..f4e688eb9 100644
--- a/library/std/src/io/buffered/tests.rs
+++ b/library/std/src/io/buffered/tests.rs
@@ -1,5 +1,7 @@
use crate::io::prelude::*;
-use crate::io::{self, BufReader, BufWriter, ErrorKind, IoSlice, LineWriter, ReadBuf, SeekFrom};
+use crate::io::{
+ self, BorrowedBuf, BufReader, BufWriter, ErrorKind, IoSlice, LineWriter, SeekFrom,
+};
use crate::mem::MaybeUninit;
use crate::panic;
use crate::sync::atomic::{AtomicUsize, Ordering};
@@ -61,48 +63,48 @@ fn test_buffered_reader_read_buf() {
let inner: &[u8] = &[5, 6, 7, 0, 1, 2, 3, 4];
let mut reader = BufReader::with_capacity(2, inner);
- let mut buf = [MaybeUninit::uninit(); 3];
- let mut buf = ReadBuf::uninit(&mut buf);
+ let buf: &mut [_] = &mut [MaybeUninit::uninit(); 3];
+ let mut buf: BorrowedBuf<'_> = buf.into();
- reader.read_buf(&mut buf).unwrap();
+ reader.read_buf(buf.unfilled()).unwrap();
assert_eq!(buf.filled(), [5, 6, 7]);
assert_eq!(reader.buffer(), []);
- let mut buf = [MaybeUninit::uninit(); 2];
- let mut buf = ReadBuf::uninit(&mut buf);
+ let buf: &mut [_] = &mut [MaybeUninit::uninit(); 2];
+ let mut buf: BorrowedBuf<'_> = buf.into();
- reader.read_buf(&mut buf).unwrap();
+ reader.read_buf(buf.unfilled()).unwrap();
assert_eq!(buf.filled(), [0, 1]);
assert_eq!(reader.buffer(), []);
- let mut buf = [MaybeUninit::uninit(); 1];
- let mut buf = ReadBuf::uninit(&mut buf);
+ let buf: &mut [_] = &mut [MaybeUninit::uninit(); 1];
+ let mut buf: BorrowedBuf<'_> = buf.into();
- reader.read_buf(&mut buf).unwrap();
+ reader.read_buf(buf.unfilled()).unwrap();
assert_eq!(buf.filled(), [2]);
assert_eq!(reader.buffer(), [3]);
- let mut buf = [MaybeUninit::uninit(); 3];
- let mut buf = ReadBuf::uninit(&mut buf);
+ let buf: &mut [_] = &mut [MaybeUninit::uninit(); 3];
+ let mut buf: BorrowedBuf<'_> = buf.into();
- reader.read_buf(&mut buf).unwrap();
+ reader.read_buf(buf.unfilled()).unwrap();
assert_eq!(buf.filled(), [3]);
assert_eq!(reader.buffer(), []);
- reader.read_buf(&mut buf).unwrap();
+ reader.read_buf(buf.unfilled()).unwrap();
assert_eq!(buf.filled(), [3, 4]);
assert_eq!(reader.buffer(), []);
buf.clear();
- reader.read_buf(&mut buf).unwrap();
+ reader.read_buf(buf.unfilled()).unwrap();
- assert_eq!(buf.filled_len(), 0);
+ assert!(buf.filled().is_empty());
}
#[test]
@@ -1037,3 +1039,27 @@ fn single_formatted_write() {
writeln!(&mut writer, "{}, {}!", "hello", "world").unwrap();
assert_eq!(writer.get_ref().events, [RecordedEvent::Write("hello, world!\n".to_string())]);
}
+
+#[test]
+fn bufreader_full_initialize() {
+ struct OneByteReader;
+ impl Read for OneByteReader {
+ fn read(&mut self, buf: &mut [u8]) -> crate::io::Result<usize> {
+ if buf.len() > 0 {
+ buf[0] = 0;
+ Ok(1)
+ } else {
+ Ok(0)
+ }
+ }
+ }
+ let mut reader = BufReader::new(OneByteReader);
+ // Nothing is initialized yet.
+ assert_eq!(reader.initialized(), 0);
+
+ let buf = reader.fill_buf().unwrap();
+ // We read one byte...
+ assert_eq!(buf.len(), 1);
+ // But we initialized the whole buffer!
+ assert_eq!(reader.initialized(), reader.capacity());
+}
diff --git a/library/std/src/io/copy.rs b/library/std/src/io/copy.rs
index 1a10245e4..38b98afff 100644
--- a/library/std/src/io/copy.rs
+++ b/library/std/src/io/copy.rs
@@ -1,4 +1,4 @@
-use super::{BufWriter, ErrorKind, Read, ReadBuf, Result, Write, DEFAULT_BUF_SIZE};
+use super::{BorrowedBuf, BufWriter, ErrorKind, Read, Result, Write, DEFAULT_BUF_SIZE};
use crate::mem::MaybeUninit;
/// Copies the entire contents of a reader into a writer.
@@ -97,37 +97,39 @@ impl<I: Write> BufferedCopySpec for BufWriter<I> {
loop {
let buf = writer.buffer_mut();
- let mut read_buf = ReadBuf::uninit(buf.spare_capacity_mut());
+ let mut read_buf: BorrowedBuf<'_> = buf.spare_capacity_mut().into();
- // SAFETY: init is either 0 or the initialized_len of the previous iteration
unsafe {
- read_buf.assume_init(init);
+ // SAFETY: init is either 0 or the init_len from the previous iteration.
+ read_buf.set_init(init);
}
if read_buf.capacity() >= DEFAULT_BUF_SIZE {
- match reader.read_buf(&mut read_buf) {
+ let mut cursor = read_buf.unfilled();
+ match reader.read_buf(cursor.reborrow()) {
Ok(()) => {
- let bytes_read = read_buf.filled_len();
+ let bytes_read = cursor.written();
if bytes_read == 0 {
return Ok(len);
}
- init = read_buf.initialized_len() - bytes_read;
+ init = read_buf.init_len() - bytes_read;
+ len += bytes_read as u64;
- // SAFETY: ReadBuf guarantees all of its filled bytes are init
+ // SAFETY: BorrowedBuf guarantees all of its filled bytes are init
unsafe { buf.set_len(buf.len() + bytes_read) };
- len += bytes_read as u64;
+
// Read again if the buffer still has enough capacity, as BufWriter itself would do
// This will occur if the reader returns short reads
- continue;
}
- Err(ref e) if e.kind() == ErrorKind::Interrupted => continue,
+ Err(ref e) if e.kind() == ErrorKind::Interrupted => {}
Err(e) => return Err(e),
}
+ } else {
+ writer.flush_buf()?;
+ init = 0;
}
-
- writer.flush_buf()?;
}
}
}
@@ -136,13 +138,13 @@ fn stack_buffer_copy<R: Read + ?Sized, W: Write + ?Sized>(
reader: &mut R,
writer: &mut W,
) -> Result<u64> {
- let mut buf = [MaybeUninit::uninit(); DEFAULT_BUF_SIZE];
- let mut buf = ReadBuf::uninit(&mut buf);
+ let buf: &mut [_] = &mut [MaybeUninit::uninit(); DEFAULT_BUF_SIZE];
+ let mut buf: BorrowedBuf<'_> = buf.into();
let mut len = 0;
loop {
- match reader.read_buf(&mut buf) {
+ match reader.read_buf(buf.unfilled()) {
Ok(()) => {}
Err(e) if e.kind() == ErrorKind::Interrupted => continue,
Err(e) => return Err(e),
diff --git a/library/std/src/io/cursor.rs b/library/std/src/io/cursor.rs
index f3fbfc447..d98ab021c 100644
--- a/library/std/src/io/cursor.rs
+++ b/library/std/src/io/cursor.rs
@@ -5,7 +5,7 @@ use crate::io::prelude::*;
use crate::alloc::Allocator;
use crate::cmp;
-use crate::io::{self, ErrorKind, IoSlice, IoSliceMut, ReadBuf, SeekFrom};
+use crate::io::{self, BorrowedCursor, ErrorKind, IoSlice, IoSliceMut, SeekFrom};
/// A `Cursor` wraps an in-memory buffer and provides it with a
/// [`Seek`] implementation.
@@ -323,12 +323,12 @@ where
Ok(n)
}
- fn read_buf(&mut self, buf: &mut ReadBuf<'_>) -> io::Result<()> {
- let prev_filled = buf.filled_len();
+ fn read_buf(&mut self, mut cursor: BorrowedCursor<'_>) -> io::Result<()> {
+ let prev_written = cursor.written();
- Read::read_buf(&mut self.fill_buf()?, buf)?;
+ Read::read_buf(&mut self.fill_buf()?, cursor.reborrow())?;
- self.pos += (buf.filled_len() - prev_filled) as u64;
+ self.pos += (cursor.written() - prev_written) as u64;
Ok(())
}
diff --git a/library/std/src/io/error.rs b/library/std/src/io/error.rs
index ff7fdcae1..29b09fcc5 100644
--- a/library/std/src/io/error.rs
+++ b/library/std/src/io/error.rs
@@ -76,6 +76,15 @@ impl fmt::Debug for Error {
}
}
+#[cfg(not(bootstrap))]
+#[stable(feature = "rust1", since = "1.0.0")]
+impl From<alloc::ffi::NulError> for Error {
+ /// Converts a [`alloc::ffi::NulError`] into a [`Error`].
+ fn from(_: alloc::ffi::NulError) -> Error {
+ const_io_error!(ErrorKind::InvalidInput, "data provided contains a nul byte")
+ }
+}
+
// Only derive debug in tests, to make sure it
// doesn't accidentally get printed.
#[cfg_attr(test, derive(Debug))]
@@ -564,6 +573,8 @@ impl Error {
/// println!("last OS error: {os_error:?}");
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
+ #[doc(alias = "GetLastError")]
+ #[doc(alias = "errno")]
#[must_use]
#[inline]
pub fn last_os_error() -> Error {
diff --git a/library/std/src/io/error/repr_bitpacked.rs b/library/std/src/io/error/repr_bitpacked.rs
index 292bf4826..781ae03ad 100644
--- a/library/std/src/io/error/repr_bitpacked.rs
+++ b/library/std/src/io/error/repr_bitpacked.rs
@@ -269,10 +269,10 @@ where
}
TAG_SIMPLE_MESSAGE => ErrorData::SimpleMessage(&*ptr.cast::<SimpleMessage>().as_ptr()),
TAG_CUSTOM => {
- // It would be correct for us to use `ptr::sub` here (see the
+ // It would be correct for us to use `ptr::byte_sub` here (see the
// comment above the `wrapping_add` call in `new_custom` for why),
// but it isn't clear that it makes a difference, so we don't.
- let custom = ptr.as_ptr().cast::<u8>().wrapping_sub(TAG_CUSTOM).cast::<Custom>();
+ let custom = ptr.as_ptr().wrapping_byte_sub(TAG_CUSTOM).cast::<Custom>();
ErrorData::Custom(make_custom(custom))
}
_ => {
diff --git a/library/std/src/io/impls.rs b/library/std/src/io/impls.rs
index 950725473..e5048dcc8 100644
--- a/library/std/src/io/impls.rs
+++ b/library/std/src/io/impls.rs
@@ -6,7 +6,7 @@ use crate::cmp;
use crate::collections::VecDeque;
use crate::fmt;
use crate::io::{
- self, BufRead, ErrorKind, IoSlice, IoSliceMut, Read, ReadBuf, Seek, SeekFrom, Write,
+ self, BorrowedCursor, BufRead, ErrorKind, IoSlice, IoSliceMut, Read, Seek, SeekFrom, Write,
};
use crate::mem;
@@ -21,8 +21,8 @@ impl<R: Read + ?Sized> Read for &mut R {
}
#[inline]
- fn read_buf(&mut self, buf: &mut ReadBuf<'_>) -> io::Result<()> {
- (**self).read_buf(buf)
+ fn read_buf(&mut self, cursor: BorrowedCursor<'_>) -> io::Result<()> {
+ (**self).read_buf(cursor)
}
#[inline]
@@ -125,8 +125,8 @@ impl<R: Read + ?Sized> Read for Box<R> {
}
#[inline]
- fn read_buf(&mut self, buf: &mut ReadBuf<'_>) -> io::Result<()> {
- (**self).read_buf(buf)
+ fn read_buf(&mut self, cursor: BorrowedCursor<'_>) -> io::Result<()> {
+ (**self).read_buf(cursor)
}
#[inline]
@@ -249,11 +249,11 @@ impl Read for &[u8] {
}
#[inline]
- fn read_buf(&mut self, buf: &mut ReadBuf<'_>) -> io::Result<()> {
- let amt = cmp::min(buf.remaining(), self.len());
+ fn read_buf(&mut self, mut cursor: BorrowedCursor<'_>) -> io::Result<()> {
+ let amt = cmp::min(cursor.capacity(), self.len());
let (a, b) = self.split_at(amt);
- buf.append(a);
+ cursor.append(a);
*self = b;
Ok(())
@@ -427,10 +427,10 @@ impl<A: Allocator> Read for VecDeque<u8, A> {
}
#[inline]
- fn read_buf(&mut self, buf: &mut ReadBuf<'_>) -> io::Result<()> {
+ fn read_buf(&mut self, cursor: BorrowedCursor<'_>) -> io::Result<()> {
let (ref mut front, _) = self.as_slices();
- let n = cmp::min(buf.remaining(), front.len());
- Read::read_buf(front, buf)?;
+ let n = cmp::min(cursor.capacity(), front.len());
+ Read::read_buf(front, cursor)?;
self.drain(..n);
Ok(())
}
diff --git a/library/std/src/io/mod.rs b/library/std/src/io/mod.rs
index 96addbd1a..eeace2c43 100644
--- a/library/std/src/io/mod.rs
+++ b/library/std/src/io/mod.rs
@@ -278,7 +278,7 @@ pub use self::{
};
#[unstable(feature = "read_buf", issue = "78485")]
-pub use self::readbuf::ReadBuf;
+pub use self::readbuf::{BorrowedBuf, BorrowedCursor};
pub(crate) use error::const_io_error;
mod buffered;
@@ -362,29 +362,30 @@ pub(crate) fn default_read_to_end<R: Read + ?Sized>(r: &mut R, buf: &mut Vec<u8>
buf.reserve(32); // buf is full, need more space
}
- let mut read_buf = ReadBuf::uninit(buf.spare_capacity_mut());
+ let mut read_buf: BorrowedBuf<'_> = buf.spare_capacity_mut().into();
// SAFETY: These bytes were initialized but not filled in the previous loop
unsafe {
- read_buf.assume_init(initialized);
+ read_buf.set_init(initialized);
}
- match r.read_buf(&mut read_buf) {
+ let mut cursor = read_buf.unfilled();
+ match r.read_buf(cursor.reborrow()) {
Ok(()) => {}
Err(e) if e.kind() == ErrorKind::Interrupted => continue,
Err(e) => return Err(e),
}
- if read_buf.filled_len() == 0 {
+ if cursor.written() == 0 {
return Ok(buf.len() - start_len);
}
// store how much was initialized but not filled
- initialized = read_buf.initialized_len() - read_buf.filled_len();
- let new_len = read_buf.filled_len() + buf.len();
+ initialized = cursor.init_ref().len();
- // SAFETY: ReadBuf's invariants mean this much memory is init
+ // SAFETY: BorrowedBuf's invariants mean this much memory is initialized.
unsafe {
+ let new_len = read_buf.filled().len() + buf.len();
buf.set_len(new_len);
}
@@ -461,12 +462,15 @@ pub(crate) fn default_read_exact<R: Read + ?Sized>(this: &mut R, mut buf: &mut [
}
}
-pub(crate) fn default_read_buf<F>(read: F, buf: &mut ReadBuf<'_>) -> Result<()>
+pub(crate) fn default_read_buf<F>(read: F, mut cursor: BorrowedCursor<'_>) -> Result<()>
where
F: FnOnce(&mut [u8]) -> Result<usize>,
{
- let n = read(buf.initialize_unfilled())?;
- buf.add_filled(n);
+ let n = read(cursor.ensure_init().init_mut())?;
+ unsafe {
+ // SAFETY: we initialised using `ensure_init` so there is no uninit data to advance to.
+ cursor.advance(n);
+ }
Ok(())
}
@@ -803,30 +807,30 @@ pub trait Read {
/// Pull some bytes from this source into the specified buffer.
///
- /// This is equivalent to the [`read`](Read::read) method, except that it is passed a [`ReadBuf`] rather than `[u8]` to allow use
+ /// This is equivalent to the [`read`](Read::read) method, except that it is passed a [`BorrowedCursor`] rather than `[u8]` to allow use
/// with uninitialized buffers. The new data will be appended to any existing contents of `buf`.
///
/// The default implementation delegates to `read`.
#[unstable(feature = "read_buf", issue = "78485")]
- fn read_buf(&mut self, buf: &mut ReadBuf<'_>) -> Result<()> {
+ fn read_buf(&mut self, buf: BorrowedCursor<'_>) -> Result<()> {
default_read_buf(|b| self.read(b), buf)
}
- /// Read the exact number of bytes required to fill `buf`.
+ /// Read the exact number of bytes required to fill `cursor`.
///
- /// This is equivalent to the [`read_exact`](Read::read_exact) method, except that it is passed a [`ReadBuf`] rather than `[u8]` to
+ /// This is equivalent to the [`read_exact`](Read::read_exact) method, except that it is passed a [`BorrowedCursor`] rather than `[u8]` to
/// allow use with uninitialized buffers.
#[unstable(feature = "read_buf", issue = "78485")]
- fn read_buf_exact(&mut self, buf: &mut ReadBuf<'_>) -> Result<()> {
- while buf.remaining() > 0 {
- let prev_filled = buf.filled().len();
- match self.read_buf(buf) {
+ fn read_buf_exact(&mut self, mut cursor: BorrowedCursor<'_>) -> Result<()> {
+ while cursor.capacity() > 0 {
+ let prev_written = cursor.written();
+ match self.read_buf(cursor.reborrow()) {
Ok(()) => {}
Err(e) if e.kind() == ErrorKind::Interrupted => continue,
Err(e) => return Err(e),
}
- if buf.filled().len() == prev_filled {
+ if cursor.written() == prev_written {
return Err(Error::new(ErrorKind::UnexpectedEof, "failed to fill buffer"));
}
}
@@ -883,6 +887,10 @@ pub trait Read {
/// The yielded item is [`Ok`] if a byte was successfully read and [`Err`]
/// otherwise. EOF is mapped to returning [`None`] from this iterator.
///
+ /// The default implementation calls `read` for each byte,
+ /// which can be very inefficient for data that's not in memory,
+ /// such as [`File`]. Consider using a [`BufReader`] in such cases.
+ ///
/// # Examples
///
/// [`File`]s implement `Read`:
@@ -895,10 +903,11 @@ pub trait Read {
/// ```no_run
/// use std::io;
/// use std::io::prelude::*;
+ /// use std::io::BufReader;
/// use std::fs::File;
///
/// fn main() -> io::Result<()> {
- /// let f = File::open("foo.txt")?;
+ /// let f = BufReader::new(File::open("foo.txt")?);
///
/// for byte in f.bytes() {
/// println!("{}", byte.unwrap());
@@ -1028,8 +1037,6 @@ pub trait Read {
/// # Examples
///
/// ```no_run
-/// #![feature(io_read_to_string)]
-///
/// # use std::io;
/// fn main() -> io::Result<()> {
/// let stdin = io::read_to_string(io::stdin())?;
@@ -1038,7 +1045,7 @@ pub trait Read {
/// Ok(())
/// }
/// ```
-#[unstable(feature = "io_read_to_string", issue = "80218")]
+#[stable(feature = "io_read_to_string", since = "1.65.0")]
pub fn read_to_string<R: Read>(mut reader: R) -> Result<String> {
let mut buf = String::new();
reader.read_to_string(&mut buf)?;
@@ -2582,50 +2589,48 @@ impl<T: Read> Read for Take<T> {
Ok(n)
}
- fn read_buf(&mut self, buf: &mut ReadBuf<'_>) -> Result<()> {
+ fn read_buf(&mut self, mut buf: BorrowedCursor<'_>) -> Result<()> {
// Don't call into inner reader at all at EOF because it may still block
if self.limit == 0 {
return Ok(());
}
- let prev_filled = buf.filled_len();
-
- if self.limit <= buf.remaining() as u64 {
+ if self.limit <= buf.capacity() as u64 {
// if we just use an as cast to convert, limit may wrap around on a 32 bit target
let limit = cmp::min(self.limit, usize::MAX as u64) as usize;
- let extra_init = cmp::min(limit as usize, buf.initialized_len() - buf.filled_len());
+ let extra_init = cmp::min(limit as usize, buf.init_ref().len());
// SAFETY: no uninit data is written to ibuf
- let ibuf = unsafe { &mut buf.unfilled_mut()[..limit] };
+ let ibuf = unsafe { &mut buf.as_mut()[..limit] };
- let mut sliced_buf = ReadBuf::uninit(ibuf);
+ let mut sliced_buf: BorrowedBuf<'_> = ibuf.into();
// SAFETY: extra_init bytes of ibuf are known to be initialized
unsafe {
- sliced_buf.assume_init(extra_init);
+ sliced_buf.set_init(extra_init);
}
- self.inner.read_buf(&mut sliced_buf)?;
+ let mut cursor = sliced_buf.unfilled();
+ self.inner.read_buf(cursor.reborrow())?;
- let new_init = sliced_buf.initialized_len();
- let filled = sliced_buf.filled_len();
+ let new_init = cursor.init_ref().len();
+ let filled = sliced_buf.len();
- // sliced_buf / ibuf must drop here
+ // cursor / sliced_buf / ibuf must drop here
- // SAFETY: new_init bytes of buf's unfilled buffer have been initialized
unsafe {
- buf.assume_init(new_init);
+ // SAFETY: filled bytes have been filled and therefore initialized
+ buf.advance(filled);
+ // SAFETY: new_init bytes of buf's unfilled buffer have been initialized
+ buf.set_init(new_init);
}
- buf.add_filled(filled);
-
self.limit -= filled as u64;
} else {
- self.inner.read_buf(buf)?;
-
- //inner may unfill
- self.limit -= buf.filled_len().saturating_sub(prev_filled) as u64;
+ let written = buf.written();
+ self.inner.read_buf(buf.reborrow())?;
+ self.limit -= (buf.written() - written) as u64;
}
Ok(())
diff --git a/library/std/src/io/readbuf.rs b/library/std/src/io/readbuf.rs
index 78d1113f8..b1a84095f 100644
--- a/library/std/src/io/readbuf.rs
+++ b/library/std/src/io/readbuf.rs
@@ -5,9 +5,10 @@ mod tests;
use crate::cmp;
use crate::fmt::{self, Debug, Formatter};
-use crate::mem::MaybeUninit;
+use crate::io::{Result, Write};
+use crate::mem::{self, MaybeUninit};
-/// A wrapper around a byte buffer that is incrementally filled and initialized.
+/// A borrowed byte buffer which is incrementally filled and initialized.
///
/// This type is a sort of "double cursor". It tracks three regions in the buffer: a region at the beginning of the
/// buffer that has been logically filled with data, a region that has been initialized at some point but not yet
@@ -20,230 +21,286 @@ use crate::mem::MaybeUninit;
/// [ filled | unfilled ]
/// [ initialized | uninitialized ]
/// ```
-pub struct ReadBuf<'a> {
- buf: &'a mut [MaybeUninit<u8>],
+///
+/// A `BorrowedBuf` is created around some existing data (or capacity for data) via a unique reference
+/// (`&mut`). The `BorrowedBuf` can be configured (e.g., using `clear` or `set_init`), but cannot be
+/// directly written. To write into the buffer, use `unfilled` to create a `BorrowedCursor`. The cursor
+/// has write-only access to the unfilled portion of the buffer (you can think of it as a
+/// write-only iterator).
+///
+/// The lifetime `'data` is a bound on the lifetime of the underlying data.
+pub struct BorrowedBuf<'data> {
+ /// The buffer's underlying data.
+ buf: &'data mut [MaybeUninit<u8>],
+ /// The length of `self.buf` which is known to be filled.
filled: usize,
- initialized: usize,
+ /// The length of `self.buf` which is known to be initialized.
+ init: usize,
}
-impl Debug for ReadBuf<'_> {
+impl Debug for BorrowedBuf<'_> {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
- f.debug_struct("ReadBuf")
- .field("init", &self.initialized())
+ f.debug_struct("BorrowedBuf")
+ .field("init", &self.init)
.field("filled", &self.filled)
.field("capacity", &self.capacity())
.finish()
}
}
-impl<'a> ReadBuf<'a> {
- /// Creates a new `ReadBuf` from a fully initialized buffer.
+/// Create a new `BorrowedBuf` from a fully initialized slice.
+impl<'data> From<&'data mut [u8]> for BorrowedBuf<'data> {
#[inline]
- pub fn new(buf: &'a mut [u8]) -> ReadBuf<'a> {
- let len = buf.len();
+ fn from(slice: &'data mut [u8]) -> BorrowedBuf<'data> {
+ let len = slice.len();
- ReadBuf {
- //SAFETY: initialized data never becoming uninitialized is an invariant of ReadBuf
- buf: unsafe { (buf as *mut [u8]).as_uninit_slice_mut().unwrap() },
+ BorrowedBuf {
+ // SAFETY: initialized data never becoming uninitialized is an invariant of BorrowedBuf
+ buf: unsafe { (slice as *mut [u8]).as_uninit_slice_mut().unwrap() },
filled: 0,
- initialized: len,
+ init: len,
}
}
+}
- /// Creates a new `ReadBuf` from a fully uninitialized buffer.
- ///
- /// Use `assume_init` if part of the buffer is known to be already initialized.
+/// Create a new `BorrowedBuf` from an uninitialized buffer.
+///
+/// Use `set_init` if part of the buffer is known to be already initialized.
+impl<'data> From<&'data mut [MaybeUninit<u8>]> for BorrowedBuf<'data> {
#[inline]
- pub fn uninit(buf: &'a mut [MaybeUninit<u8>]) -> ReadBuf<'a> {
- ReadBuf { buf, filled: 0, initialized: 0 }
+ fn from(buf: &'data mut [MaybeUninit<u8>]) -> BorrowedBuf<'data> {
+ BorrowedBuf { buf, filled: 0, init: 0 }
}
+}
+impl<'data> BorrowedBuf<'data> {
/// Returns the total capacity of the buffer.
#[inline]
pub fn capacity(&self) -> usize {
self.buf.len()
}
+ /// Returns the length of the filled part of the buffer.
+ #[inline]
+ pub fn len(&self) -> usize {
+ self.filled
+ }
+
+ /// Returns the length of the initialized part of the buffer.
+ #[inline]
+ pub fn init_len(&self) -> usize {
+ self.init
+ }
+
/// Returns a shared reference to the filled portion of the buffer.
#[inline]
pub fn filled(&self) -> &[u8] {
- //SAFETY: We only slice the filled part of the buffer, which is always valid
+ // SAFETY: We only slice the filled part of the buffer, which is always valid
unsafe { MaybeUninit::slice_assume_init_ref(&self.buf[0..self.filled]) }
}
- /// Returns a mutable reference to the filled portion of the buffer.
+ /// Returns a cursor over the unfilled part 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]) }
+ pub fn unfilled<'this>(&'this mut self) -> BorrowedCursor<'this> {
+ BorrowedCursor {
+ start: self.filled,
+ // SAFETY: we never assign into `BorrowedCursor::buf`, so treating its
+ // lifetime covariantly is safe.
+ buf: unsafe {
+ mem::transmute::<&'this mut BorrowedBuf<'data>, &'this mut BorrowedBuf<'this>>(self)
+ },
+ }
}
- /// Returns a shared reference to the initialized portion of the buffer.
+ /// Clears the buffer, resetting the filled region to empty.
///
- /// This includes the filled portion.
+ /// The number of initialized bytes is not changed, and the contents of the buffer are not modified.
#[inline]
- pub fn initialized(&self) -> &[u8] {
- //SAFETY: We only slice the initialized part of the buffer, which is always valid
- unsafe { MaybeUninit::slice_assume_init_ref(&self.buf[0..self.initialized]) }
+ pub fn clear(&mut self) -> &mut Self {
+ self.filled = 0;
+ self
}
- /// Returns a mutable reference to the initialized portion of the buffer.
+ /// Asserts that the first `n` bytes of the buffer are initialized.
///
- /// This includes the filled portion.
- #[inline]
- pub fn initialized_mut(&mut self) -> &mut [u8] {
- //SAFETY: We only slice the initialized part of the buffer, which is always valid
- unsafe { MaybeUninit::slice_assume_init_mut(&mut self.buf[0..self.initialized]) }
- }
-
- /// Returns a mutable reference to the unfilled part of the buffer without ensuring that it has been fully
- /// initialized.
+ /// `BorrowedBuf` assumes that bytes are never de-initialized, so this method does nothing when called with fewer
+ /// bytes than are already known to be initialized.
///
/// # Safety
///
- /// The caller must not de-initialize portions of the buffer that have already been initialized.
+ /// The caller must ensure that the first `n` unfilled bytes of the buffer have already been initialized.
#[inline]
- pub unsafe fn unfilled_mut(&mut self) -> &mut [MaybeUninit<u8>] {
- &mut self.buf[self.filled..]
+ pub unsafe fn set_init(&mut self, n: usize) -> &mut Self {
+ self.init = cmp::max(self.init, n);
+ self
}
+}
- /// Returns a mutable reference to the uninitialized part of the buffer.
+/// A writeable view of the unfilled portion of a [`BorrowedBuf`](BorrowedBuf).
+///
+/// Provides access to the initialized and uninitialized parts of the underlying `BorrowedBuf`.
+/// Data can be written directly to the cursor by using [`append`](BorrowedCursor::append) or
+/// indirectly by getting a slice of part or all of the cursor and writing into the slice. In the
+/// indirect case, the caller must call [`advance`](BorrowedCursor::advance) after writing to inform
+/// the cursor how many bytes have been written.
+///
+/// Once data is written to the cursor, it becomes part of the filled portion of the underlying
+/// `BorrowedBuf` and can no longer be accessed or re-written by the cursor. I.e., the cursor tracks
+/// the unfilled part of the underlying `BorrowedBuf`.
+///
+/// The lifetime `'a` is a bound on the lifetime of the underlying buffer (which means it is a bound
+/// on the data in that buffer by transitivity).
+#[derive(Debug)]
+pub struct BorrowedCursor<'a> {
+ /// The underlying buffer.
+ // Safety invariant: we treat the type of buf as covariant in the lifetime of `BorrowedBuf` when
+ // we create a `BorrowedCursor`. This is only safe if we never replace `buf` by assigning into
+ // it, so don't do that!
+ buf: &'a mut BorrowedBuf<'a>,
+ /// The length of the filled portion of the underlying buffer at the time of the cursor's
+ /// creation.
+ start: usize,
+}
+
+impl<'a> BorrowedCursor<'a> {
+ /// Reborrow this cursor by cloning it with a smaller lifetime.
///
- /// It is safe to uninitialize any of these bytes.
+ /// Since a cursor maintains unique access to its underlying buffer, the borrowed cursor is
+ /// not accessible while the new cursor exists.
#[inline]
- pub fn uninitialized_mut(&mut self) -> &mut [MaybeUninit<u8>] {
- &mut self.buf[self.initialized..]
+ pub fn reborrow<'this>(&'this mut self) -> BorrowedCursor<'this> {
+ BorrowedCursor {
+ // SAFETY: we never assign into `BorrowedCursor::buf`, so treating its
+ // lifetime covariantly is safe.
+ buf: unsafe {
+ mem::transmute::<&'this mut BorrowedBuf<'a>, &'this mut BorrowedBuf<'this>>(
+ self.buf,
+ )
+ },
+ start: self.start,
+ }
}
- /// Returns a mutable reference to the unfilled part of the buffer, ensuring it is fully initialized.
- ///
- /// Since `ReadBuf` tracks the region of the buffer that has been initialized, this is effectively "free" after
- /// the first use.
+ /// Returns the available space in the cursor.
#[inline]
- pub fn initialize_unfilled(&mut self) -> &mut [u8] {
- // should optimize out the assertion
- self.initialize_unfilled_to(self.remaining())
+ pub fn capacity(&self) -> usize {
+ self.buf.capacity() - self.buf.filled
}
- /// Returns a mutable reference to the first `n` bytes of the unfilled part of the buffer, ensuring it is
- /// fully initialized.
- ///
- /// # Panics
+ /// Returns the number of bytes written to this cursor since it was created from a `BorrowedBuf`.
///
- /// Panics if `self.remaining()` is less than `n`.
+ /// Note that if this cursor is a reborrowed clone of another, then the count returned is the
+ /// count written via either cursor, not the count since the cursor was reborrowed.
#[inline]
- pub fn initialize_unfilled_to(&mut self, n: usize) -> &mut [u8] {
- assert!(self.remaining() >= n);
-
- let extra_init = self.initialized - self.filled;
- // If we don't have enough initialized, do zeroing
- if n > extra_init {
- let uninit = n - extra_init;
- let unfilled = &mut self.uninitialized_mut()[0..uninit];
-
- for byte in unfilled.iter_mut() {
- byte.write(0);
- }
-
- // SAFETY: we just initialized uninit bytes, and the previous bytes were already init
- unsafe {
- self.assume_init(n);
- }
- }
-
- let filled = self.filled;
+ pub fn written(&self) -> usize {
+ self.buf.filled - self.start
+ }
- &mut self.initialized_mut()[filled..filled + n]
+ /// Returns a shared reference to the initialized portion of the cursor.
+ #[inline]
+ pub fn init_ref(&self) -> &[u8] {
+ // SAFETY: We only slice the initialized part of the buffer, which is always valid
+ unsafe { MaybeUninit::slice_assume_init_ref(&self.buf.buf[self.buf.filled..self.buf.init]) }
}
- /// Returns the number of bytes at the end of the slice that have not yet been filled.
+ /// Returns a mutable reference to the initialized portion of the cursor.
#[inline]
- pub fn remaining(&self) -> usize {
- self.capacity() - self.filled
+ pub fn init_mut(&mut self) -> &mut [u8] {
+ // SAFETY: We only slice the initialized part of the buffer, which is always valid
+ unsafe {
+ MaybeUninit::slice_assume_init_mut(&mut self.buf.buf[self.buf.filled..self.buf.init])
+ }
}
- /// Clears the buffer, resetting the filled region to empty.
+ /// Returns a mutable reference to the uninitialized part of the cursor.
///
- /// The number of initialized bytes is not changed, and the contents of the buffer are not modified.
+ /// It is safe to uninitialize any of these bytes.
#[inline]
- pub fn clear(&mut self) -> &mut Self {
- self.set_filled(0) // The assertion in `set_filled` is optimized out
+ pub fn uninit_mut(&mut self) -> &mut [MaybeUninit<u8>] {
+ &mut self.buf.buf[self.buf.init..]
}
- /// Increases the size of the filled region of the buffer.
- ///
- /// The number of initialized bytes is not changed.
+ /// Returns a mutable reference to the whole cursor.
///
- /// # Panics
+ /// # Safety
///
- /// Panics if the filled region of the buffer would become larger than the initialized region.
+ /// The caller must not uninitialize any bytes in the initialized portion of the cursor.
#[inline]
- pub fn add_filled(&mut self, n: usize) -> &mut Self {
- self.set_filled(self.filled + n)
+ pub unsafe fn as_mut(&mut self) -> &mut [MaybeUninit<u8>] {
+ &mut self.buf.buf[self.buf.filled..]
}
- /// Sets the size of the filled region of the buffer.
+ /// Advance the cursor by asserting that `n` bytes have been filled.
///
- /// The number of initialized bytes is not changed.
+ /// After advancing, the `n` bytes are no longer accessible via the cursor and can only be
+ /// accessed via the underlying buffer. I.e., the buffer's filled portion grows by `n` elements
+ /// and its unfilled portion (and the capacity of this cursor) shrinks by `n` elements.
///
- /// Note that this can be used to *shrink* the filled region of the buffer in addition to growing it (for
- /// example, by a `Read` implementation that compresses data in-place).
- ///
- /// # Panics
+ /// # Safety
///
- /// Panics if the filled region of the buffer would become larger than the initialized region.
+ /// The caller must ensure that the first `n` bytes of the cursor have been properly
+ /// initialised.
+ #[inline]
+ pub unsafe fn advance(&mut self, n: usize) -> &mut Self {
+ self.buf.filled += n;
+ self.buf.init = cmp::max(self.buf.init, self.buf.filled);
+ self
+ }
+
+ /// Initializes all bytes in the cursor.
#[inline]
- pub fn set_filled(&mut self, n: usize) -> &mut Self {
- assert!(n <= self.initialized);
+ pub fn ensure_init(&mut self) -> &mut Self {
+ for byte in self.uninit_mut() {
+ byte.write(0);
+ }
+ self.buf.init = self.buf.capacity();
- self.filled = n;
self
}
- /// Asserts that the first `n` unfilled bytes of the buffer are initialized.
+ /// Asserts that the first `n` unfilled bytes of the cursor are initialized.
///
- /// `ReadBuf` assumes that bytes are never de-initialized, so this method does nothing when called with fewer
- /// bytes than are already known to be initialized.
+ /// `BorrowedBuf` assumes that bytes are never de-initialized, so this method does nothing when
+ /// called with fewer bytes than are already known to be initialized.
///
/// # Safety
///
- /// The caller must ensure that the first `n` unfilled bytes of the buffer have already been initialized.
+ /// The caller must ensure that the first `n` bytes of the buffer have already been initialized.
#[inline]
- pub unsafe fn assume_init(&mut self, n: usize) -> &mut Self {
- self.initialized = cmp::max(self.initialized, self.filled + n);
+ pub unsafe fn set_init(&mut self, n: usize) -> &mut Self {
+ self.buf.init = cmp::max(self.buf.init, self.buf.filled + n);
self
}
- /// Appends data to the buffer, advancing the written position and possibly also the initialized position.
+ /// Appends data to the cursor, advancing position within its buffer.
///
/// # Panics
///
- /// Panics if `self.remaining()` is less than `buf.len()`.
+ /// Panics if `self.capacity()` is less than `buf.len()`.
#[inline]
pub fn append(&mut self, buf: &[u8]) {
- assert!(self.remaining() >= buf.len());
+ assert!(self.capacity() >= buf.len());
// SAFETY: we do not de-initialize any of the elements of the slice
unsafe {
- MaybeUninit::write_slice(&mut self.unfilled_mut()[..buf.len()], buf);
+ MaybeUninit::write_slice(&mut self.as_mut()[..buf.len()], buf);
}
// SAFETY: We just added the entire contents of buf to the filled section.
unsafe {
- self.assume_init(buf.len());
+ self.set_init(buf.len());
}
- self.add_filled(buf.len());
+ self.buf.filled += buf.len();
}
+}
- /// Returns the amount of bytes that have been filled.
- #[inline]
- pub fn filled_len(&self) -> usize {
- self.filled
+impl<'a> Write for BorrowedCursor<'a> {
+ fn write(&mut self, buf: &[u8]) -> Result<usize> {
+ self.append(buf);
+ Ok(buf.len())
}
- /// Returns the amount of bytes that have been initialized.
- #[inline]
- pub fn initialized_len(&self) -> usize {
- self.initialized
+ fn flush(&mut self) -> Result<()> {
+ Ok(())
}
}
diff --git a/library/std/src/io/readbuf/tests.rs b/library/std/src/io/readbuf/tests.rs
index 3b7a5a56d..cc1b423f2 100644
--- a/library/std/src/io/readbuf/tests.rs
+++ b/library/std/src/io/readbuf/tests.rs
@@ -1,181 +1,175 @@
-use super::ReadBuf;
+use super::BorrowedBuf;
use crate::mem::MaybeUninit;
-/// Test that ReadBuf has the correct numbers when created with new
+/// Test that BorrowedBuf has the correct numbers when created with new
#[test]
fn new() {
- let mut buf = [0; 16];
- let rbuf = ReadBuf::new(&mut buf);
+ let buf: &mut [_] = &mut [0; 16];
+ let mut rbuf: BorrowedBuf<'_> = buf.into();
- assert_eq!(rbuf.filled_len(), 0);
- assert_eq!(rbuf.initialized_len(), 16);
+ assert_eq!(rbuf.filled().len(), 0);
+ assert_eq!(rbuf.init_len(), 16);
assert_eq!(rbuf.capacity(), 16);
- assert_eq!(rbuf.remaining(), 16);
+ assert_eq!(rbuf.unfilled().capacity(), 16);
}
-/// Test that ReadBuf has the correct numbers when created with uninit
+/// Test that BorrowedBuf has the correct numbers when created with uninit
#[test]
fn uninit() {
- let mut buf = [MaybeUninit::uninit(); 16];
- let rbuf = ReadBuf::uninit(&mut buf);
+ let buf: &mut [_] = &mut [MaybeUninit::uninit(); 16];
+ let mut rbuf: BorrowedBuf<'_> = buf.into();
- assert_eq!(rbuf.filled_len(), 0);
- assert_eq!(rbuf.initialized_len(), 0);
+ assert_eq!(rbuf.filled().len(), 0);
+ assert_eq!(rbuf.init_len(), 0);
assert_eq!(rbuf.capacity(), 16);
- assert_eq!(rbuf.remaining(), 16);
+ assert_eq!(rbuf.unfilled().capacity(), 16);
}
#[test]
fn initialize_unfilled() {
- let mut buf = [MaybeUninit::uninit(); 16];
- let mut rbuf = ReadBuf::uninit(&mut buf);
+ let buf: &mut [_] = &mut [MaybeUninit::uninit(); 16];
+ let mut rbuf: BorrowedBuf<'_> = buf.into();
- rbuf.initialize_unfilled();
+ rbuf.unfilled().ensure_init();
- assert_eq!(rbuf.initialized_len(), 16);
+ assert_eq!(rbuf.init_len(), 16);
}
#[test]
-fn initialize_unfilled_to() {
- let mut buf = [MaybeUninit::uninit(); 16];
- let mut rbuf = ReadBuf::uninit(&mut buf);
+fn addvance_filled() {
+ let buf: &mut [_] = &mut [0; 16];
+ let mut rbuf: BorrowedBuf<'_> = buf.into();
- rbuf.initialize_unfilled_to(8);
-
- assert_eq!(rbuf.initialized_len(), 8);
-
- rbuf.initialize_unfilled_to(4);
-
- assert_eq!(rbuf.initialized_len(), 8);
-
- rbuf.set_filled(8);
-
- rbuf.initialize_unfilled_to(6);
-
- assert_eq!(rbuf.initialized_len(), 14);
-
- rbuf.initialize_unfilled_to(8);
-
- assert_eq!(rbuf.initialized_len(), 16);
-}
-
-#[test]
-fn add_filled() {
- let mut buf = [0; 16];
- let mut rbuf = ReadBuf::new(&mut buf);
-
- rbuf.add_filled(1);
-
- assert_eq!(rbuf.filled_len(), 1);
- assert_eq!(rbuf.remaining(), 15);
-}
-
-#[test]
-#[should_panic]
-fn add_filled_panic() {
- let mut buf = [MaybeUninit::uninit(); 16];
- let mut rbuf = ReadBuf::uninit(&mut buf);
-
- rbuf.add_filled(1);
-}
-
-#[test]
-fn set_filled() {
- let mut buf = [0; 16];
- let mut rbuf = ReadBuf::new(&mut buf);
-
- rbuf.set_filled(16);
-
- assert_eq!(rbuf.filled_len(), 16);
- assert_eq!(rbuf.remaining(), 0);
-
- rbuf.set_filled(6);
-
- assert_eq!(rbuf.filled_len(), 6);
- assert_eq!(rbuf.remaining(), 10);
-}
-
-#[test]
-#[should_panic]
-fn set_filled_panic() {
- let mut buf = [MaybeUninit::uninit(); 16];
- let mut rbuf = ReadBuf::uninit(&mut buf);
+ unsafe {
+ rbuf.unfilled().advance(1);
+ }
- rbuf.set_filled(16);
+ assert_eq!(rbuf.filled().len(), 1);
+ assert_eq!(rbuf.unfilled().capacity(), 15);
}
#[test]
fn clear() {
- let mut buf = [255; 16];
- let mut rbuf = ReadBuf::new(&mut buf);
+ let buf: &mut [_] = &mut [255; 16];
+ let mut rbuf: BorrowedBuf<'_> = buf.into();
- rbuf.set_filled(16);
+ unsafe {
+ rbuf.unfilled().advance(16);
+ }
- assert_eq!(rbuf.filled_len(), 16);
- assert_eq!(rbuf.remaining(), 0);
+ assert_eq!(rbuf.filled().len(), 16);
+ assert_eq!(rbuf.unfilled().capacity(), 0);
rbuf.clear();
- assert_eq!(rbuf.filled_len(), 0);
- assert_eq!(rbuf.remaining(), 16);
+ assert_eq!(rbuf.filled().len(), 0);
+ assert_eq!(rbuf.unfilled().capacity(), 16);
- assert_eq!(rbuf.initialized(), [255; 16]);
+ assert_eq!(rbuf.unfilled().init_ref(), [255; 16]);
}
#[test]
-fn assume_init() {
- let mut buf = [MaybeUninit::uninit(); 16];
- let mut rbuf = ReadBuf::uninit(&mut buf);
+fn set_init() {
+ let buf: &mut [_] = &mut [MaybeUninit::uninit(); 16];
+ let mut rbuf: BorrowedBuf<'_> = buf.into();
unsafe {
- rbuf.assume_init(8);
+ rbuf.set_init(8);
}
- assert_eq!(rbuf.initialized_len(), 8);
+ assert_eq!(rbuf.init_len(), 8);
- rbuf.add_filled(4);
+ unsafe {
+ rbuf.unfilled().advance(4);
+ }
unsafe {
- rbuf.assume_init(2);
+ rbuf.set_init(2);
}
- assert_eq!(rbuf.initialized_len(), 8);
+ assert_eq!(rbuf.init_len(), 8);
unsafe {
- rbuf.assume_init(8);
+ rbuf.set_init(8);
}
- assert_eq!(rbuf.initialized_len(), 12);
+ assert_eq!(rbuf.init_len(), 8);
}
#[test]
fn append() {
- let mut buf = [MaybeUninit::new(255); 16];
- let mut rbuf = ReadBuf::uninit(&mut buf);
+ let buf: &mut [_] = &mut [MaybeUninit::new(255); 16];
+ let mut rbuf: BorrowedBuf<'_> = buf.into();
- rbuf.append(&[0; 8]);
+ rbuf.unfilled().append(&[0; 8]);
- assert_eq!(rbuf.initialized_len(), 8);
- assert_eq!(rbuf.filled_len(), 8);
+ assert_eq!(rbuf.init_len(), 8);
+ assert_eq!(rbuf.filled().len(), 8);
assert_eq!(rbuf.filled(), [0; 8]);
rbuf.clear();
- rbuf.append(&[1; 16]);
+ rbuf.unfilled().append(&[1; 16]);
- assert_eq!(rbuf.initialized_len(), 16);
- assert_eq!(rbuf.filled_len(), 16);
+ assert_eq!(rbuf.init_len(), 16);
+ assert_eq!(rbuf.filled().len(), 16);
assert_eq!(rbuf.filled(), [1; 16]);
}
#[test]
-fn filled_mut() {
- let mut buf = [0; 16];
- let mut rbuf = ReadBuf::new(&mut buf);
+fn reborrow_written() {
+ let buf: &mut [_] = &mut [MaybeUninit::new(0); 32];
+ let mut buf: BorrowedBuf<'_> = buf.into();
+
+ let mut cursor = buf.unfilled();
+ cursor.append(&[1; 16]);
+
+ let mut cursor2 = cursor.reborrow();
+ cursor2.append(&[2; 16]);
+
+ assert_eq!(cursor2.written(), 32);
+ assert_eq!(cursor.written(), 32);
+
+ assert_eq!(buf.unfilled().written(), 0);
+ assert_eq!(buf.init_len(), 32);
+ assert_eq!(buf.filled().len(), 32);
+ let filled = buf.filled();
+ assert_eq!(&filled[..16], [1; 16]);
+ assert_eq!(&filled[16..], [2; 16]);
+}
+
+#[test]
+fn cursor_set_init() {
+ let buf: &mut [_] = &mut [MaybeUninit::uninit(); 16];
+ let mut rbuf: BorrowedBuf<'_> = buf.into();
+
+ unsafe {
+ rbuf.unfilled().set_init(8);
+ }
- rbuf.add_filled(8);
+ assert_eq!(rbuf.init_len(), 8);
+ assert_eq!(rbuf.unfilled().init_ref().len(), 8);
+ assert_eq!(rbuf.unfilled().init_mut().len(), 8);
+ assert_eq!(rbuf.unfilled().uninit_mut().len(), 8);
+ assert_eq!(unsafe { rbuf.unfilled().as_mut() }.len(), 16);
+
+ unsafe {
+ rbuf.unfilled().advance(4);
+ }
- let filled = rbuf.filled().to_vec();
+ unsafe {
+ rbuf.unfilled().set_init(2);
+ }
+
+ assert_eq!(rbuf.init_len(), 8);
+
+ unsafe {
+ rbuf.unfilled().set_init(8);
+ }
- assert_eq!(&*filled, &*rbuf.filled_mut());
+ assert_eq!(rbuf.init_len(), 12);
+ assert_eq!(rbuf.unfilled().init_ref().len(), 8);
+ assert_eq!(rbuf.unfilled().init_mut().len(), 8);
+ assert_eq!(rbuf.unfilled().uninit_mut().len(), 4);
+ assert_eq!(unsafe { rbuf.unfilled().as_mut() }.len(), 12);
}
diff --git a/library/std/src/io/stdio.rs b/library/std/src/io/stdio.rs
index 4d3736f79..2dc12a18a 100644
--- a/library/std/src/io/stdio.rs
+++ b/library/std/src/io/stdio.rs
@@ -8,7 +8,6 @@ use crate::io::prelude::*;
use crate::cell::{Cell, RefCell};
use crate::fmt;
use crate::io::{self, BufReader, IoSlice, IoSliceMut, LineWriter, Lines};
-use crate::pin::Pin;
use crate::sync::atomic::{AtomicBool, Ordering};
use crate::sync::{Arc, Mutex, MutexGuard, OnceLock};
use crate::sys::stdio;
@@ -526,7 +525,7 @@ pub struct Stdout {
// FIXME: this should be LineWriter or BufWriter depending on the state of
// stdout (tty or not). Note that if this is not line buffered it
// should also flush-on-panic or some form of flush-on-abort.
- inner: Pin<&'static ReentrantMutex<RefCell<LineWriter<StdoutRaw>>>>,
+ inner: &'static ReentrantMutex<RefCell<LineWriter<StdoutRaw>>>,
}
/// A locked reference to the [`Stdout`] handle.
@@ -603,22 +602,27 @@ static STDOUT: OnceLock<ReentrantMutex<RefCell<LineWriter<StdoutRaw>>>> = OnceLo
#[stable(feature = "rust1", since = "1.0.0")]
pub fn stdout() -> Stdout {
Stdout {
- inner: Pin::static_ref(&STDOUT).get_or_init_pin(
- || unsafe { ReentrantMutex::new(RefCell::new(LineWriter::new(stdout_raw()))) },
- |mutex| unsafe { mutex.init() },
- ),
+ inner: STDOUT
+ .get_or_init(|| ReentrantMutex::new(RefCell::new(LineWriter::new(stdout_raw())))),
}
}
+// Flush the data and disable buffering during shutdown
+// by replacing the line writer by one with zero
+// buffering capacity.
pub fn cleanup() {
- if let Some(instance) = STDOUT.get() {
- // Flush the data and disable buffering during shutdown
- // by replacing the line writer by one with zero
- // buffering capacity.
+ let mut initialized = false;
+ let stdout = STDOUT.get_or_init(|| {
+ initialized = true;
+ ReentrantMutex::new(RefCell::new(LineWriter::with_capacity(0, stdout_raw())))
+ });
+
+ if !initialized {
+ // The buffer was previously initialized, overwrite it here.
// We use try_lock() instead of lock(), because someone
// might have leaked a StdoutLock, which would
// otherwise cause a deadlock here.
- if let Some(lock) = Pin::static_ref(instance).try_lock() {
+ if let Some(lock) = stdout.try_lock() {
*lock.borrow_mut() = LineWriter::with_capacity(0, stdout_raw());
}
}
@@ -761,7 +765,7 @@ impl fmt::Debug for StdoutLock<'_> {
/// standard library or via raw Windows API calls, will fail.
#[stable(feature = "rust1", since = "1.0.0")]
pub struct Stderr {
- inner: Pin<&'static ReentrantMutex<RefCell<StderrRaw>>>,
+ inner: &'static ReentrantMutex<RefCell<StderrRaw>>,
}
/// A locked reference to the [`Stderr`] handle.
@@ -834,16 +838,12 @@ pub struct StderrLock<'a> {
#[stable(feature = "rust1", since = "1.0.0")]
pub fn stderr() -> Stderr {
// Note that unlike `stdout()` we don't use `at_exit` here to register a
- // destructor. Stderr is not buffered , so there's no need to run a
+ // destructor. Stderr is not buffered, so there's no need to run a
// destructor for flushing the buffer
- static INSTANCE: OnceLock<ReentrantMutex<RefCell<StderrRaw>>> = OnceLock::new();
+ static INSTANCE: ReentrantMutex<RefCell<StderrRaw>> =
+ ReentrantMutex::new(RefCell::new(stderr_raw()));
- Stderr {
- inner: Pin::static_ref(&INSTANCE).get_or_init_pin(
- || unsafe { ReentrantMutex::new(RefCell::new(stderr_raw())) },
- |mutex| unsafe { mutex.init() },
- ),
- }
+ Stderr { inner: &INSTANCE }
}
impl Stderr {
@@ -986,12 +986,15 @@ pub fn set_output_capture(sink: Option<LocalStream>) -> Option<LocalStream> {
/// otherwise. `label` identifies the stream in a panic message.
///
/// This function is used to print error messages, so it takes extra
-/// care to avoid causing a panic when `local_s` is unusable.
-/// For instance, if the TLS key for the local stream is
-/// already destroyed, or if the local stream is locked by another
-/// thread, it will just fall back to the global stream.
+/// care to avoid causing a panic when `OUTPUT_CAPTURE` is unusable.
+/// For instance, if the TLS key for output capturing is already destroyed, or
+/// if the local stream is in use by another thread, it will just fall back to
+/// the global stream.
///
/// However, if the actual I/O causes an error, this function does panic.
+///
+/// Writing to non-blocking stdout/stderr can cause an error, which will lead
+/// this function to panic.
fn print_to<T>(args: fmt::Arguments<'_>, global_s: fn() -> T, label: &str)
where
T: Write,
diff --git a/library/std/src/io/tests.rs b/library/std/src/io/tests.rs
index f357f33ec..f4a886d88 100644
--- a/library/std/src/io/tests.rs
+++ b/library/std/src/io/tests.rs
@@ -1,4 +1,4 @@
-use super::{repeat, Cursor, ReadBuf, SeekFrom};
+use super::{repeat, BorrowedBuf, Cursor, SeekFrom};
use crate::cmp::{self, min};
use crate::io::{self, IoSlice, IoSliceMut};
use crate::io::{BufRead, BufReader, Read, Seek, Write};
@@ -94,7 +94,7 @@ fn read_to_end() {
assert_eq!(c.read_to_end(&mut v).unwrap(), 1);
assert_eq!(v, b"1");
- let cap = 1024 * 1024;
+ let cap = if cfg!(miri) { 1024 } else { 1024 * 1024 };
let data = (0..cap).map(|i| (i / 3) as u8).collect::<Vec<_>>();
let mut v = Vec::new();
let (a, b) = data.split_at(data.len() / 2);
@@ -159,24 +159,24 @@ fn read_exact_slice() {
#[test]
fn read_buf_exact() {
- let mut buf = [0; 4];
- let mut buf = ReadBuf::new(&mut buf);
+ let buf: &mut [_] = &mut [0; 4];
+ let mut buf: BorrowedBuf<'_> = buf.into();
let mut c = Cursor::new(&b""[..]);
- assert_eq!(c.read_buf_exact(&mut buf).unwrap_err().kind(), io::ErrorKind::UnexpectedEof);
+ assert_eq!(c.read_buf_exact(buf.unfilled()).unwrap_err().kind(), io::ErrorKind::UnexpectedEof);
let mut c = Cursor::new(&b"123456789"[..]);
- c.read_buf_exact(&mut buf).unwrap();
+ c.read_buf_exact(buf.unfilled()).unwrap();
assert_eq!(buf.filled(), b"1234");
buf.clear();
- c.read_buf_exact(&mut buf).unwrap();
+ c.read_buf_exact(buf.unfilled()).unwrap();
assert_eq!(buf.filled(), b"5678");
buf.clear();
- assert_eq!(c.read_buf_exact(&mut buf).unwrap_err().kind(), io::ErrorKind::UnexpectedEof);
+ assert_eq!(c.read_buf_exact(buf.unfilled()).unwrap_err().kind(), io::ErrorKind::UnexpectedEof);
}
#[test]
@@ -309,6 +309,7 @@ fn chain_zero_length_read_is_not_eof() {
#[bench]
#[cfg_attr(target_os = "emscripten", ignore)]
+#[cfg_attr(miri, ignore)] // Miri isn't fast...
fn bench_read_to_end(b: &mut test::Bencher) {
b.iter(|| {
let mut lr = repeat(1).take(10000000);
@@ -614,10 +615,10 @@ fn bench_take_read(b: &mut test::Bencher) {
#[bench]
fn bench_take_read_buf(b: &mut test::Bencher) {
b.iter(|| {
- let mut buf = [MaybeUninit::uninit(); 64];
+ let buf: &mut [_] = &mut [MaybeUninit::uninit(); 64];
- let mut rbuf = ReadBuf::uninit(&mut buf);
+ let mut buf: BorrowedBuf<'_> = buf.into();
- [255; 128].take(64).read_buf(&mut rbuf).unwrap();
+ [255; 128].take(64).read_buf(buf.unfilled()).unwrap();
});
}
diff --git a/library/std/src/io/util.rs b/library/std/src/io/util.rs
index c1300cd67..f076ee092 100644
--- a/library/std/src/io/util.rs
+++ b/library/std/src/io/util.rs
@@ -5,7 +5,7 @@ mod tests;
use crate::fmt;
use crate::io::{
- self, BufRead, IoSlice, IoSliceMut, Read, ReadBuf, Seek, SeekFrom, SizeHint, Write,
+ self, BorrowedCursor, BufRead, IoSlice, IoSliceMut, Read, Seek, SeekFrom, SizeHint, Write,
};
/// A reader which is always at EOF.
@@ -47,7 +47,7 @@ impl Read for Empty {
}
#[inline]
- fn read_buf(&mut self, _buf: &mut ReadBuf<'_>) -> io::Result<()> {
+ fn read_buf(&mut self, _cursor: BorrowedCursor<'_>) -> io::Result<()> {
Ok(())
}
}
@@ -130,21 +130,19 @@ impl Read for Repeat {
Ok(buf.len())
}
- fn read_buf(&mut self, buf: &mut ReadBuf<'_>) -> io::Result<()> {
+ fn read_buf(&mut self, mut buf: BorrowedCursor<'_>) -> io::Result<()> {
// SAFETY: No uninit bytes are being written
- for slot in unsafe { buf.unfilled_mut() } {
+ for slot in unsafe { buf.as_mut() } {
slot.write(self.byte);
}
- let remaining = buf.remaining();
+ let remaining = buf.capacity();
// SAFETY: the entire unfilled portion of buf has been initialized
unsafe {
- buf.assume_init(remaining);
+ buf.advance(remaining);
}
- buf.add_filled(remaining);
-
Ok(())
}
diff --git a/library/std/src/io/util/tests.rs b/library/std/src/io/util/tests.rs
index 08972a59a..ce5e2c9da 100644
--- a/library/std/src/io/util/tests.rs
+++ b/library/std/src/io/util/tests.rs
@@ -1,7 +1,7 @@
use crate::cmp::{max, min};
use crate::io::prelude::*;
use crate::io::{
- copy, empty, repeat, sink, BufWriter, Empty, ReadBuf, Repeat, Result, SeekFrom, Sink,
+ copy, empty, repeat, sink, BorrowedBuf, BufWriter, Empty, Repeat, Result, SeekFrom, Sink,
DEFAULT_BUF_SIZE,
};
@@ -79,29 +79,29 @@ fn empty_reads() {
assert_eq!(e.read(&mut [0; 1024]).unwrap(), 0);
assert_eq!(e.by_ref().read(&mut [0; 1024]).unwrap(), 0);
- let mut buf = [];
- let mut buf = ReadBuf::uninit(&mut buf);
- e.read_buf(&mut buf).unwrap();
- assert_eq!(buf.filled_len(), 0);
- assert_eq!(buf.initialized_len(), 0);
-
- let mut buf = [MaybeUninit::uninit()];
- let mut buf = ReadBuf::uninit(&mut buf);
- e.read_buf(&mut buf).unwrap();
- assert_eq!(buf.filled_len(), 0);
- assert_eq!(buf.initialized_len(), 0);
-
- let mut buf = [MaybeUninit::uninit(); 1024];
- let mut buf = ReadBuf::uninit(&mut buf);
- e.read_buf(&mut buf).unwrap();
- assert_eq!(buf.filled_len(), 0);
- assert_eq!(buf.initialized_len(), 0);
-
- let mut buf = [MaybeUninit::uninit(); 1024];
- let mut buf = ReadBuf::uninit(&mut buf);
- e.by_ref().read_buf(&mut buf).unwrap();
- assert_eq!(buf.filled_len(), 0);
- assert_eq!(buf.initialized_len(), 0);
+ let buf: &mut [MaybeUninit<_>] = &mut [];
+ let mut buf: BorrowedBuf<'_> = buf.into();
+ e.read_buf(buf.unfilled()).unwrap();
+ assert_eq!(buf.len(), 0);
+ assert_eq!(buf.init_len(), 0);
+
+ let buf: &mut [_] = &mut [MaybeUninit::uninit()];
+ let mut buf: BorrowedBuf<'_> = buf.into();
+ e.read_buf(buf.unfilled()).unwrap();
+ assert_eq!(buf.len(), 0);
+ assert_eq!(buf.init_len(), 0);
+
+ let buf: &mut [_] = &mut [MaybeUninit::uninit(); 1024];
+ let mut buf: BorrowedBuf<'_> = buf.into();
+ e.read_buf(buf.unfilled()).unwrap();
+ assert_eq!(buf.len(), 0);
+ assert_eq!(buf.init_len(), 0);
+
+ let buf: &mut [_] = &mut [MaybeUninit::uninit(); 1024];
+ let mut buf: BorrowedBuf<'_> = buf.into();
+ e.by_ref().read_buf(buf.unfilled()).unwrap();
+ assert_eq!(buf.len(), 0);
+ assert_eq!(buf.init_len(), 0);
}
#[test]