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/buffered/bufreader.rs25
-rw-r--r--library/std/src/io/copy.rs74
-rw-r--r--library/std/src/io/copy/tests.rs12
-rw-r--r--library/std/src/io/impls.rs32
-rw-r--r--library/std/src/io/mod.rs67
-rw-r--r--library/std/src/io/readbuf.rs317
-rw-r--r--library/std/src/io/readbuf/tests.rs175
-rw-r--r--library/std/src/io/stdio.rs2
8 files changed, 190 insertions, 514 deletions
diff --git a/library/std/src/io/buffered/bufreader.rs b/library/std/src/io/buffered/bufreader.rs
index 7097dfef8..55aafc3db 100644
--- a/library/std/src/io/buffered/bufreader.rs
+++ b/library/std/src/io/buffered/bufreader.rs
@@ -2,7 +2,8 @@ mod buffer;
use crate::fmt;
use crate::io::{
- self, BorrowedCursor, BufRead, IoSliceMut, Read, Seek, SeekFrom, SizeHint, DEFAULT_BUF_SIZE,
+ self, uninlined_slow_read_byte, BorrowedCursor, BufRead, IoSliceMut, Read, Seek, SeekFrom,
+ SizeHint, SpecReadByte, DEFAULT_BUF_SIZE,
};
use buffer::Buffer;
@@ -259,6 +260,22 @@ impl<R: ?Sized + Seek> BufReader<R> {
}
}
+impl<R> SpecReadByte for BufReader<R>
+where
+ Self: Read,
+{
+ #[inline]
+ fn spec_read_byte(&mut self) -> Option<io::Result<u8>> {
+ let mut byte = 0;
+ if self.buf.consume_with(1, |claimed| byte = claimed[0]) {
+ return Some(Ok(byte));
+ }
+
+ // Fallback case, only reached once per buffer refill.
+ uninlined_slow_read_byte(self)
+ }
+}
+
#[stable(feature = "rust1", since = "1.0.0")]
impl<R: ?Sized + Read> Read for BufReader<R> {
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
@@ -269,10 +286,8 @@ impl<R: ?Sized + Read> Read for BufReader<R> {
self.discard_buffer();
return self.inner.read(buf);
}
- let nread = {
- let mut rem = self.fill_buf()?;
- rem.read(buf)?
- };
+ let mut rem = self.fill_buf()?;
+ let nread = rem.read(buf)?;
self.consume(nread);
Ok(nread)
}
diff --git a/library/std/src/io/copy.rs b/library/std/src/io/copy.rs
index eafd078a7..4d51a719f 100644
--- a/library/std/src/io/copy.rs
+++ b/library/std/src/io/copy.rs
@@ -1,5 +1,7 @@
use super::{BorrowedBuf, BufReader, BufWriter, Read, Result, Write, DEFAULT_BUF_SIZE};
use crate::alloc::Allocator;
+use crate::cmp;
+use crate::cmp::min;
use crate::collections::VecDeque;
use crate::io::IoSlice;
use crate::mem::MaybeUninit;
@@ -254,6 +256,78 @@ 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 inflating empty/small vecs before we have determined that there's anything to read
+ if self.capacity() < DEFAULT_BUF_SIZE {
+ let stack_read_limit = DEFAULT_BUF_SIZE as u64;
+ bytes = stack_buffer_copy(&mut reader.take(stack_read_limit), self)?;
+ // fewer bytes than requested -> EOF reached
+ if bytes < stack_read_limit {
+ return Ok(bytes);
+ }
+ }
+
+ // don't immediately offer the vec's whole spare capacity, otherwise
+ // we might have to fully initialize it if the reader doesn't have a custom read_buf() impl
+ let mut max_read_size = DEFAULT_BUF_SIZE;
+
+ loop {
+ self.reserve(DEFAULT_BUF_SIZE);
+ let mut initialized_spare_capacity = 0;
+
+ loop {
+ let buf = self.spare_capacity_mut();
+ let read_size = min(max_read_size, buf.len());
+ let mut buf = BorrowedBuf::from(&mut buf[..read_size]);
+ // SAFETY: init is either 0 or the init_len from the previous iteration.
+ unsafe {
+ buf.set_init(initialized_spare_capacity);
+ }
+ match reader.read_buf(buf.unfilled()) {
+ Ok(()) => {
+ let bytes_read = buf.len();
+
+ // EOF
+ if bytes_read == 0 {
+ return Ok(bytes);
+ }
+
+ // the reader is returning short reads but it doesn't call ensure_init()
+ if buf.init_len() < buf.capacity() {
+ max_read_size = usize::MAX;
+ }
+ // the reader hasn't returned short reads so far
+ if bytes_read == buf.capacity() {
+ max_read_size *= 2;
+ }
+
+ initialized_spare_capacity = buf.init_len() - bytes_read;
+ bytes += bytes_read as u64;
+ // 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() + bytes_read) };
+
+ // spare capacity full, reserve more
+ if self.len() == self.capacity() {
+ break;
+ }
+ }
+ Err(e) if e.is_interrupted() => continue,
+ Err(e) => return Err(e),
+ }
+ }
+ }
+ }
+}
+
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 d9998e87c..af137eaf8 100644
--- a/library/std/src/io/copy/tests.rs
+++ b/library/std/src/io/copy/tests.rs
@@ -81,6 +81,18 @@ 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 {
diff --git a/library/std/src/io/impls.rs b/library/std/src/io/impls.rs
index a7428776d..d8c8d933e 100644
--- a/library/std/src/io/impls.rs
+++ b/library/std/src/io/impls.rs
@@ -475,6 +475,24 @@ impl<A: Allocator> Read for VecDeque<u8, A> {
}
}
+/// BufRead is implemented for `VecDeque<u8>` by reading bytes from the front of the `VecDeque`.
+#[stable(feature = "vecdeque_buf_read", since = "1.75.0")]
+impl<A: Allocator> BufRead for VecDeque<u8, A> {
+ /// Returns the contents of the "front" slice as returned by
+ /// [`as_slices`][`VecDeque::as_slices`]. If the contained byte slices of the `VecDeque` are
+ /// discontiguous, multiple calls to `fill_buf` will be needed to read the entire content.
+ #[inline]
+ fn fill_buf(&mut self) -> io::Result<&[u8]> {
+ let (front, _) = self.as_slices();
+ Ok(front)
+ }
+
+ #[inline]
+ fn consume(&mut self, amt: usize) {
+ self.drain(..amt);
+ }
+}
+
/// Write is implemented for `VecDeque<u8>` by appending to the `VecDeque`, growing it as needed.
#[stable(feature = "vecdeque_read_write", since = "1.63.0")]
impl<A: Allocator> Write for VecDeque<u8, A> {
@@ -510,3 +528,17 @@ impl<A: Allocator> Write for VecDeque<u8, A> {
Ok(())
}
}
+
+#[unstable(feature = "read_buf", issue = "78485")]
+impl<'a> io::Write for core::io::BorrowedCursor<'a> {
+ fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
+ let amt = cmp::min(buf.len(), self.capacity());
+ self.append(&buf[..amt]);
+ Ok(amt)
+ }
+
+ #[inline]
+ fn flush(&mut self) -> io::Result<()> {
+ Ok(())
+ }
+}
diff --git a/library/std/src/io/mod.rs b/library/std/src/io/mod.rs
index 604b795cd..7d70a0bac 100644
--- a/library/std/src/io/mod.rs
+++ b/library/std/src/io/mod.rs
@@ -317,6 +317,7 @@ pub use self::stdio::set_output_capture;
#[stable(feature = "is_terminal", since = "1.70.0")]
pub use self::stdio::IsTerminal;
#[unstable(feature = "print_internals", issue = "none")]
+#[doc(hidden)]
pub use self::stdio::{_eprint, _print};
#[stable(feature = "rust1", since = "1.0.0")]
pub use self::{
@@ -329,7 +330,7 @@ pub use self::{
};
#[unstable(feature = "read_buf", issue = "78485")]
-pub use self::readbuf::{BorrowedBuf, BorrowedCursor};
+pub use core::io::{BorrowedBuf, BorrowedCursor};
pub(crate) use error::const_io_error;
mod buffered;
@@ -338,7 +339,6 @@ mod cursor;
mod error;
mod impls;
pub mod prelude;
-mod readbuf;
mod stdio;
mod util;
@@ -513,8 +513,7 @@ pub(crate) fn default_read_exact<R: Read + ?Sized>(this: &mut R, mut buf: &mut [
match this.read(buf) {
Ok(0) => break,
Ok(n) => {
- let tmp = buf;
- buf = &mut tmp[n..];
+ buf = &mut buf[n..];
}
Err(ref e) if e.is_interrupted() => {}
Err(e) => return Err(e),
@@ -1141,10 +1140,10 @@ pub fn read_to_string<R: Read>(mut reader: R) -> Result<String> {
#[repr(transparent)]
pub struct IoSliceMut<'a>(sys::io::IoSliceMut<'a>);
-#[stable(feature = "iovec-send-sync", since = "1.44.0")]
+#[stable(feature = "iovec_send_sync", since = "1.44.0")]
unsafe impl<'a> Send for IoSliceMut<'a> {}
-#[stable(feature = "iovec-send-sync", since = "1.44.0")]
+#[stable(feature = "iovec_send_sync", since = "1.44.0")]
unsafe impl<'a> Sync for IoSliceMut<'a> {}
#[stable(feature = "iovec", since = "1.36.0")]
@@ -1284,10 +1283,10 @@ impl<'a> DerefMut for IoSliceMut<'a> {
#[repr(transparent)]
pub struct IoSlice<'a>(sys::io::IoSlice<'a>);
-#[stable(feature = "iovec-send-sync", since = "1.44.0")]
+#[stable(feature = "iovec_send_sync", since = "1.44.0")]
unsafe impl<'a> Send for IoSlice<'a> {}
-#[stable(feature = "iovec-send-sync", since = "1.44.0")]
+#[stable(feature = "iovec_send_sync", since = "1.44.0")]
unsafe impl<'a> Sync for IoSlice<'a> {}
#[stable(feature = "iovec", since = "1.36.0")]
@@ -1830,6 +1829,7 @@ pub trait Write {
/// }
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
+#[cfg_attr(not(test), rustc_diagnostic_item = "IoSeek")]
pub trait Seek {
/// Seek to an offset, in bytes, in a stream.
///
@@ -2777,23 +2777,55 @@ pub struct Bytes<R> {
impl<R: Read> Iterator for Bytes<R> {
type Item = Result<u8>;
+ // Not `#[inline]`. This function gets inlined even without it, but having
+ // the inline annotation can result in worse code generation. See #116785.
fn next(&mut self) -> Option<Result<u8>> {
- let mut byte = 0;
- loop {
- return match self.inner.read(slice::from_mut(&mut byte)) {
- Ok(0) => None,
- Ok(..) => Some(Ok(byte)),
- Err(ref e) if e.is_interrupted() => continue,
- Err(e) => Some(Err(e)),
- };
- }
+ SpecReadByte::spec_read_byte(&mut self.inner)
}
+ #[inline]
fn size_hint(&self) -> (usize, Option<usize>) {
SizeHint::size_hint(&self.inner)
}
}
+/// For the specialization of `Bytes::next`.
+trait SpecReadByte {
+ fn spec_read_byte(&mut self) -> Option<Result<u8>>;
+}
+
+impl<R> SpecReadByte for R
+where
+ Self: Read,
+{
+ #[inline]
+ default fn spec_read_byte(&mut self) -> Option<Result<u8>> {
+ inlined_slow_read_byte(self)
+ }
+}
+
+/// Read a single byte in a slow, generic way. This is used by the default
+/// `spec_read_byte`.
+#[inline]
+fn inlined_slow_read_byte<R: Read>(reader: &mut R) -> Option<Result<u8>> {
+ let mut byte = 0;
+ loop {
+ return match reader.read(slice::from_mut(&mut byte)) {
+ Ok(0) => None,
+ Ok(..) => Some(Ok(byte)),
+ Err(ref e) if e.is_interrupted() => continue,
+ Err(e) => Some(Err(e)),
+ };
+ }
+}
+
+// Used by `BufReader::spec_read_byte`, for which the `inline(ever)` is
+// important.
+#[inline(never)]
+fn uninlined_slow_read_byte<R: Read>(reader: &mut R) -> Option<Result<u8>> {
+ inlined_slow_read_byte(reader)
+}
+
trait SizeHint {
fn lower_bound(&self) -> usize;
@@ -2893,6 +2925,7 @@ impl<B: BufRead> Iterator for Split<B> {
/// [`lines`]: BufRead::lines
#[stable(feature = "rust1", since = "1.0.0")]
#[derive(Debug)]
+#[cfg_attr(not(test), rustc_diagnostic_item = "IoLines")]
pub struct Lines<B> {
buf: B,
}
diff --git a/library/std/src/io/readbuf.rs b/library/std/src/io/readbuf.rs
deleted file mode 100644
index 034ddd8df..000000000
--- a/library/std/src/io/readbuf.rs
+++ /dev/null
@@ -1,317 +0,0 @@
-#![unstable(feature = "read_buf", issue = "78485")]
-
-#[cfg(test)]
-mod tests;
-
-use crate::fmt::{self, Debug, Formatter};
-use crate::io::{Result, Write};
-use crate::mem::{self, MaybeUninit};
-use crate::{cmp, ptr};
-
-/// 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
-/// logically filled, and a region at the end that is fully uninitialized. The filled region is guaranteed to be a
-/// subset of the initialized region.
-///
-/// In summary, the contents of the buffer can be visualized as:
-/// ```not_rust
-/// [ capacity ]
-/// [ filled | unfilled ]
-/// [ initialized | uninitialized ]
-/// ```
-///
-/// 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,
- /// The length of `self.buf` which is known to be initialized.
- init: usize,
-}
-
-impl Debug for BorrowedBuf<'_> {
- fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
- f.debug_struct("BorrowedBuf")
- .field("init", &self.init)
- .field("filled", &self.filled)
- .field("capacity", &self.capacity())
- .finish()
- }
-}
-
-/// Create a new `BorrowedBuf` from a fully initialized slice.
-impl<'data> From<&'data mut [u8]> for BorrowedBuf<'data> {
- #[inline]
- fn from(slice: &'data mut [u8]) -> BorrowedBuf<'data> {
- let len = slice.len();
-
- 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,
- init: len,
- }
- }
-}
-
-/// 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]
- 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
- 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> {
- 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)
- },
- }
- }
-
- /// Clears the buffer, resetting the filled region to empty.
- ///
- /// The number of initialized bytes is not changed, and the contents of the buffer are not modified.
- #[inline]
- pub fn clear(&mut self) -> &mut Self {
- self.filled = 0;
- self
- }
-
- /// Asserts that the first `n` bytes of the buffer are 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.
- #[inline]
- pub unsafe fn set_init(&mut self, n: usize) -> &mut Self {
- self.init = cmp::max(self.init, n);
- self
- }
-}
-
-/// 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.
- ///
- /// Since a cursor maintains unique access to its underlying buffer, the borrowed cursor is
- /// not accessible while the new cursor exists.
- #[inline]
- 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 the available space in the cursor.
- #[inline]
- pub fn capacity(&self) -> usize {
- self.buf.capacity() - self.buf.filled
- }
-
- /// Returns the number of bytes written to this cursor since it was created from a `BorrowedBuf`.
- ///
- /// 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 written(&self) -> usize {
- self.buf.filled - self.start
- }
-
- /// 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 a mutable reference to the initialized portion of the cursor.
- #[inline]
- 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])
- }
- }
-
- /// Returns a mutable reference to the uninitialized part of the cursor.
- ///
- /// It is safe to uninitialize any of these bytes.
- #[inline]
- pub fn uninit_mut(&mut self) -> &mut [MaybeUninit<u8>] {
- &mut self.buf.buf[self.buf.init..]
- }
-
- /// Returns a mutable reference to the whole cursor.
- ///
- /// # Safety
- ///
- /// The caller must not uninitialize any bytes in the initialized portion of the cursor.
- #[inline]
- pub unsafe fn as_mut(&mut self) -> &mut [MaybeUninit<u8>] {
- &mut self.buf.buf[self.buf.filled..]
- }
-
- /// Advance the cursor by asserting that `n` bytes have been filled.
- ///
- /// 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.
- ///
- /// # Safety
- ///
- /// 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 ensure_init(&mut self) -> &mut Self {
- let uninit = self.uninit_mut();
- // SAFETY: 0 is a valid value for MaybeUninit<u8> and the length matches the allocation
- // since it is comes from a slice reference.
- unsafe {
- ptr::write_bytes(uninit.as_mut_ptr(), 0, uninit.len());
- }
- self.buf.init = self.buf.capacity();
-
- self
- }
-
- /// Asserts that the first `n` unfilled bytes of the cursor are 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` bytes of the buffer have already been initialized.
- #[inline]
- 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 cursor, advancing position within its buffer.
- ///
- /// # Panics
- ///
- /// Panics if `self.capacity()` is less than `buf.len()`.
- #[inline]
- pub fn append(&mut self, buf: &[u8]) {
- assert!(self.capacity() >= buf.len());
-
- // SAFETY: we do not de-initialize any of the elements of the slice
- unsafe {
- 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.set_init(buf.len());
- }
- self.buf.filled += buf.len();
- }
-}
-
-impl<'a> Write for BorrowedCursor<'a> {
- fn write(&mut self, buf: &[u8]) -> Result<usize> {
- self.append(buf);
- Ok(buf.len())
- }
-
- #[inline]
- fn flush(&mut self) -> Result<()> {
- Ok(())
- }
-}
diff --git a/library/std/src/io/readbuf/tests.rs b/library/std/src/io/readbuf/tests.rs
deleted file mode 100644
index 89a2f6b22..000000000
--- a/library/std/src/io/readbuf/tests.rs
+++ /dev/null
@@ -1,175 +0,0 @@
-use super::BorrowedBuf;
-use crate::mem::MaybeUninit;
-
-/// Test that BorrowedBuf has the correct numbers when created with new
-#[test]
-fn new() {
- let buf: &mut [_] = &mut [0; 16];
- let mut rbuf: BorrowedBuf<'_> = buf.into();
-
- assert_eq!(rbuf.filled().len(), 0);
- assert_eq!(rbuf.init_len(), 16);
- assert_eq!(rbuf.capacity(), 16);
- assert_eq!(rbuf.unfilled().capacity(), 16);
-}
-
-/// Test that BorrowedBuf has the correct numbers when created with uninit
-#[test]
-fn uninit() {
- let buf: &mut [_] = &mut [MaybeUninit::uninit(); 16];
- let mut rbuf: BorrowedBuf<'_> = buf.into();
-
- assert_eq!(rbuf.filled().len(), 0);
- assert_eq!(rbuf.init_len(), 0);
- assert_eq!(rbuf.capacity(), 16);
- assert_eq!(rbuf.unfilled().capacity(), 16);
-}
-
-#[test]
-fn initialize_unfilled() {
- let buf: &mut [_] = &mut [MaybeUninit::uninit(); 16];
- let mut rbuf: BorrowedBuf<'_> = buf.into();
-
- rbuf.unfilled().ensure_init();
-
- assert_eq!(rbuf.init_len(), 16);
-}
-
-#[test]
-fn advance_filled() {
- let buf: &mut [_] = &mut [0; 16];
- let mut rbuf: BorrowedBuf<'_> = buf.into();
-
- unsafe {
- rbuf.unfilled().advance(1);
- }
-
- assert_eq!(rbuf.filled().len(), 1);
- assert_eq!(rbuf.unfilled().capacity(), 15);
-}
-
-#[test]
-fn clear() {
- let buf: &mut [_] = &mut [255; 16];
- let mut rbuf: BorrowedBuf<'_> = buf.into();
-
- unsafe {
- rbuf.unfilled().advance(16);
- }
-
- assert_eq!(rbuf.filled().len(), 16);
- assert_eq!(rbuf.unfilled().capacity(), 0);
-
- rbuf.clear();
-
- assert_eq!(rbuf.filled().len(), 0);
- assert_eq!(rbuf.unfilled().capacity(), 16);
-
- assert_eq!(rbuf.unfilled().init_ref(), [255; 16]);
-}
-
-#[test]
-fn set_init() {
- let buf: &mut [_] = &mut [MaybeUninit::uninit(); 16];
- let mut rbuf: BorrowedBuf<'_> = buf.into();
-
- unsafe {
- rbuf.set_init(8);
- }
-
- assert_eq!(rbuf.init_len(), 8);
-
- unsafe {
- rbuf.unfilled().advance(4);
- }
-
- unsafe {
- rbuf.set_init(2);
- }
-
- assert_eq!(rbuf.init_len(), 8);
-
- unsafe {
- rbuf.set_init(8);
- }
-
- assert_eq!(rbuf.init_len(), 8);
-}
-
-#[test]
-fn append() {
- let buf: &mut [_] = &mut [MaybeUninit::new(255); 16];
- let mut rbuf: BorrowedBuf<'_> = buf.into();
-
- rbuf.unfilled().append(&[0; 8]);
-
- assert_eq!(rbuf.init_len(), 8);
- assert_eq!(rbuf.filled().len(), 8);
- assert_eq!(rbuf.filled(), [0; 8]);
-
- rbuf.clear();
-
- rbuf.unfilled().append(&[1; 16]);
-
- assert_eq!(rbuf.init_len(), 16);
- assert_eq!(rbuf.filled().len(), 16);
- assert_eq!(rbuf.filled(), [1; 16]);
-}
-
-#[test]
-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);
- }
-
- 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);
- }
-
- unsafe {
- rbuf.unfilled().set_init(2);
- }
-
- assert_eq!(rbuf.init_len(), 8);
-
- unsafe {
- rbuf.unfilled().set_init(8);
- }
-
- 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 9098d36ee..05b21eeb4 100644
--- a/library/std/src/io/stdio.rs
+++ b/library/std/src/io/stdio.rs
@@ -611,6 +611,7 @@ static STDOUT: OnceLock<ReentrantMutex<RefCell<LineWriter<StdoutRaw>>>> = OnceLo
/// ```
#[must_use]
#[stable(feature = "rust1", since = "1.0.0")]
+#[cfg_attr(not(test), rustc_diagnostic_item = "io_stdout")]
pub fn stdout() -> Stdout {
Stdout {
inner: STDOUT
@@ -847,6 +848,7 @@ pub struct StderrLock<'a> {
/// ```
#[must_use]
#[stable(feature = "rust1", since = "1.0.0")]
+#[cfg_attr(not(test), rustc_diagnostic_item = "io_stderr")]
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