about summary refs log tree commit diff
path: root/library/std/src/io
diff options
context:
space:
mode:
authorLaurențiu Nicola <lnicola@dend.ro>2024-08-13 17:58:52 +0300
committerLaurențiu Nicola <lnicola@dend.ro>2024-08-13 17:58:52 +0300
commit28af7e09581c3b39cdbf2850df2f157690ab7e56 (patch)
tree76c5e72c0570998ece04f11ac90e09b5d2613abc /library/std/src/io
parentddb8551e03a1310a841da05b0418b49fd6287482 (diff)
parent80eb5a8e910e5185d47cdefe3732d839c78a5e7e (diff)
Merge from rust-lang/rust
Diffstat (limited to 'library/std/src/io')
-rw-r--r--library/std/src/io/buffered/bufreader.rs37
-rw-r--r--library/std/src/io/buffered/bufreader/buffer.rs21
-rw-r--r--library/std/src/io/buffered/bufwriter.rs4
-rw-r--r--library/std/src/io/buffered/linewriter.rs3
-rw-r--r--library/std/src/io/buffered/linewritershim.rs43
-rw-r--r--library/std/src/io/buffered/mod.rs14
-rw-r--r--library/std/src/io/buffered/tests.rs3
-rw-r--r--library/std/src/io/copy/tests.rs7
-rw-r--r--library/std/src/io/cursor.rs68
-rw-r--r--library/std/src/io/error.rs9
-rw-r--r--library/std/src/io/error/repr_bitpacked.rs3
-rw-r--r--library/std/src/io/error/tests.rs6
-rw-r--r--library/std/src/io/impls.rs5
-rw-r--r--library/std/src/io/mod.rs52
-rw-r--r--library/std/src/io/stdio.rs5
-rw-r--r--library/std/src/io/tests.rs11
-rw-r--r--library/std/src/io/util/tests.rs1
17 files changed, 171 insertions, 121 deletions
diff --git a/library/std/src/io/buffered/bufreader.rs b/library/std/src/io/buffered/bufreader.rs
index 0cdc49c87d8..0b12e5777c8 100644
--- a/library/std/src/io/buffered/bufreader.rs
+++ b/library/std/src/io/buffered/bufreader.rs
@@ -1,11 +1,12 @@
 mod buffer;
 
+use buffer::Buffer;
+
 use crate::fmt;
 use crate::io::{
     self, uninlined_slow_read_byte, BorrowedCursor, BufRead, IoSliceMut, Read, Seek, SeekFrom,
     SizeHint, SpecReadByte, DEFAULT_BUF_SIZE,
 };
-use buffer::Buffer;
 
 /// The `BufReader<R>` struct adds buffering to any reader.
 ///
@@ -93,6 +94,40 @@ impl<R: Read> BufReader<R> {
     pub fn with_capacity(capacity: usize, inner: R) -> BufReader<R> {
         BufReader { inner, buf: Buffer::with_capacity(capacity) }
     }
+
+    /// Attempt to look ahead `n` bytes.
+    ///
+    /// `n` must be less than `capacity`.
+    ///
+    /// ## Examples
+    ///
+    /// ```rust
+    /// #![feature(bufreader_peek)]
+    /// use std::io::{Read, BufReader};
+    ///
+    /// let mut bytes = &b"oh, hello"[..];
+    /// let mut rdr = BufReader::with_capacity(6, &mut bytes);
+    /// assert_eq!(rdr.peek(2).unwrap(), b"oh");
+    /// let mut buf = [0; 4];
+    /// rdr.read(&mut buf[..]).unwrap();
+    /// assert_eq!(&buf, b"oh, ");
+    /// assert_eq!(rdr.peek(2).unwrap(), b"he");
+    /// let mut s = String::new();
+    /// rdr.read_to_string(&mut s).unwrap();
+    /// assert_eq!(&s, "hello");
+    /// ```
+    #[unstable(feature = "bufreader_peek", issue = "128405")]
+    pub fn peek(&mut self, n: usize) -> io::Result<&[u8]> {
+        assert!(n <= self.capacity());
+        while n > self.buf.buffer().len() {
+            if self.buf.pos() > 0 {
+                self.buf.backshift();
+            }
+            self.buf.read_more(&mut self.inner)?;
+            debug_assert_eq!(self.buf.pos(), 0);
+        }
+        Ok(&self.buf.buffer()[..n])
+    }
 }
 
 impl<R: ?Sized> BufReader<R> {
diff --git a/library/std/src/io/buffered/bufreader/buffer.rs b/library/std/src/io/buffered/bufreader/buffer.rs
index 796137c0123..ccd67fafb45 100644
--- a/library/std/src/io/buffered/bufreader/buffer.rs
+++ b/library/std/src/io/buffered/bufreader/buffer.rs
@@ -97,6 +97,27 @@ impl Buffer {
         self.pos = self.pos.saturating_sub(amt);
     }
 
+    /// Read more bytes into the buffer without discarding any of its contents
+    pub fn read_more(&mut self, mut reader: impl Read) -> io::Result<()> {
+        let mut buf = BorrowedBuf::from(&mut self.buf[self.pos..]);
+        let old_init = self.initialized - self.pos;
+        unsafe {
+            buf.set_init(old_init);
+        }
+        reader.read_buf(buf.unfilled())?;
+        self.filled += buf.len();
+        self.initialized += buf.init_len() - old_init;
+        Ok(())
+    }
+
+    /// Remove bytes that have already been read from the buffer.
+    pub fn backshift(&mut self) {
+        self.buf.copy_within(self.pos.., 0);
+        self.initialized -= self.pos;
+        self.filled -= self.pos;
+        self.pos = 0;
+    }
+
     #[inline]
     pub fn fill_buf(&mut self, mut reader: impl Read) -> io::Result<&[u8]> {
         // If we've reached the end of our internal buffer then we need to fetch
diff --git a/library/std/src/io/buffered/bufwriter.rs b/library/std/src/io/buffered/bufwriter.rs
index a8680e9b6ea..21650d46744 100644
--- a/library/std/src/io/buffered/bufwriter.rs
+++ b/library/std/src/io/buffered/bufwriter.rs
@@ -1,10 +1,8 @@
-use crate::error;
-use crate::fmt;
 use crate::io::{
     self, ErrorKind, IntoInnerError, IoSlice, Seek, SeekFrom, Write, DEFAULT_BUF_SIZE,
 };
 use crate::mem::{self, ManuallyDrop};
-use crate::ptr;
+use crate::{error, fmt, ptr};
 
 /// Wraps a writer and buffers its output.
 ///
diff --git a/library/std/src/io/buffered/linewriter.rs b/library/std/src/io/buffered/linewriter.rs
index 3d4ae704193..cc6921b86dd 100644
--- a/library/std/src/io/buffered/linewriter.rs
+++ b/library/std/src/io/buffered/linewriter.rs
@@ -1,5 +1,6 @@
 use crate::fmt;
-use crate::io::{self, buffered::LineWriterShim, BufWriter, IntoInnerError, IoSlice, Write};
+use crate::io::buffered::LineWriterShim;
+use crate::io::{self, BufWriter, IntoInnerError, IoSlice, Write};
 
 /// Wraps a writer and buffers output to it, flushing whenever a newline
 /// (`0x0a`, `'\n'`) is detected.
diff --git a/library/std/src/io/buffered/linewritershim.rs b/library/std/src/io/buffered/linewritershim.rs
index c3ac7855d44..3d04ccd1c7d 100644
--- a/library/std/src/io/buffered/linewritershim.rs
+++ b/library/std/src/io/buffered/linewritershim.rs
@@ -1,7 +1,9 @@
-use crate::io::{self, BufWriter, IoSlice, Write};
 use core::slice::memchr;
 
+use crate::io::{self, BufWriter, IoSlice, Write};
+
 /// Private helper struct for implementing the line-buffered writing logic.
+///
 /// This shim temporarily wraps a BufWriter, and uses its internals to
 /// implement a line-buffered writer (specifically by using the internal
 /// methods like write_to_buf and flush_buf). In this way, a more
@@ -20,27 +22,27 @@ impl<'a, W: ?Sized + Write> LineWriterShim<'a, W> {
         Self { buffer }
     }
 
-    /// Get a reference to the inner writer (that is, the writer
+    /// Gets a reference to the inner writer (that is, the writer
     /// wrapped by the BufWriter).
     fn inner(&self) -> &W {
         self.buffer.get_ref()
     }
 
-    /// Get a mutable reference to the inner writer (that is, the writer
+    /// Gets a mutable reference to the inner writer (that is, the writer
     /// wrapped by the BufWriter). Be careful with this writer, as writes to
     /// it will bypass the buffer.
     fn inner_mut(&mut self) -> &mut W {
         self.buffer.get_mut()
     }
 
-    /// Get the content currently buffered in self.buffer
+    /// Gets the content currently buffered in self.buffer
     fn buffered(&self) -> &[u8] {
         self.buffer.buffer()
     }
 
-    /// Flush the buffer iff the last byte is a newline (indicating that an
+    /// Flushes the buffer iff the last byte is a newline (indicating that an
     /// earlier write only succeeded partially, and we want to retry flushing
-    /// the buffered line before continuing with a subsequent write)
+    /// the buffered line before continuing with a subsequent write).
     fn flush_if_completed_line(&mut self) -> io::Result<()> {
         match self.buffered().last().copied() {
             Some(b'\n') => self.buffer.flush_buf(),
@@ -50,10 +52,11 @@ impl<'a, W: ?Sized + Write> LineWriterShim<'a, W> {
 }
 
 impl<'a, W: ?Sized + Write> Write for LineWriterShim<'a, W> {
-    /// Write some data into this BufReader with line buffering. This means
-    /// that, if any newlines are present in the data, the data up to the last
-    /// newline is sent directly to the underlying writer, and data after it
-    /// is buffered. Returns the number of bytes written.
+    /// Writes some data into this BufReader with line buffering.
+    ///
+    /// This means that, if any newlines are present in the data, the data up to
+    /// the last newline is sent directly to the underlying writer, and data
+    /// after it is buffered. Returns the number of bytes written.
     ///
     /// This function operates on a "best effort basis"; in keeping with the
     /// convention of `Write::write`, it makes at most one attempt to write
@@ -136,11 +139,12 @@ impl<'a, W: ?Sized + Write> Write for LineWriterShim<'a, W> {
         self.buffer.flush()
     }
 
-    /// Write some vectored data into this BufReader with line buffering. This
-    /// means that, if any newlines are present in the data, the data up to
-    /// and including the buffer containing the last newline is sent directly
-    /// to the inner writer, and the data after it is buffered. Returns the
-    /// number of bytes written.
+    /// Writes some vectored data into this BufReader with line buffering.
+    ///
+    /// This means that, if any newlines are present in the data, the data up to
+    /// and including the buffer containing the last newline is sent directly to
+    /// the inner writer, and the data after it is buffered. Returns the number
+    /// of bytes written.
     ///
     /// This function operates on a "best effort basis"; in keeping with the
     /// convention of `Write::write`, it makes at most one attempt to write
@@ -245,10 +249,11 @@ impl<'a, W: ?Sized + Write> Write for LineWriterShim<'a, W> {
         self.inner().is_write_vectored()
     }
 
-    /// Write some data into this BufReader with line buffering. This means
-    /// that, if any newlines are present in the data, the data up to the last
-    /// newline is sent directly to the underlying writer, and data after it
-    /// is buffered.
+    /// Writes some data into this BufReader with line buffering.
+    ///
+    /// This means that, if any newlines are present in the data, the data up to
+    /// the last newline is sent directly to the underlying writer, and data
+    /// after it is buffered.
     ///
     /// Because this function attempts to send completed lines to the underlying
     /// writer, it will also flush the existing buffer if it contains any
diff --git a/library/std/src/io/buffered/mod.rs b/library/std/src/io/buffered/mod.rs
index 100dab1e249..475d877528f 100644
--- a/library/std/src/io/buffered/mod.rs
+++ b/library/std/src/io/buffered/mod.rs
@@ -8,16 +8,14 @@ mod linewritershim;
 #[cfg(test)]
 mod tests;
 
-use crate::error;
-use crate::fmt;
-use crate::io::Error;
+#[stable(feature = "bufwriter_into_parts", since = "1.56.0")]
+pub use bufwriter::WriterPanicked;
+use linewritershim::LineWriterShim;
 
 #[stable(feature = "rust1", since = "1.0.0")]
 pub use self::{bufreader::BufReader, bufwriter::BufWriter, linewriter::LineWriter};
-use linewritershim::LineWriterShim;
-
-#[stable(feature = "bufwriter_into_parts", since = "1.56.0")]
-pub use bufwriter::WriterPanicked;
+use crate::io::Error;
+use crate::{error, fmt};
 
 /// An error returned by [`BufWriter::into_inner`] which combines an error that
 /// happened while writing out the buffer, and the buffered writer object
@@ -48,7 +46,7 @@ pub use bufwriter::WriterPanicked;
 pub struct IntoInnerError<W>(W, Error);
 
 impl<W> IntoInnerError<W> {
-    /// Construct a new IntoInnerError
+    /// Constructs a new IntoInnerError
     fn new(writer: W, error: Error) -> Self {
         Self(writer, error)
     }
diff --git a/library/std/src/io/buffered/tests.rs b/library/std/src/io/buffered/tests.rs
index ab66deaf31d..d89ecd317d6 100644
--- a/library/std/src/io/buffered/tests.rs
+++ b/library/std/src/io/buffered/tests.rs
@@ -3,9 +3,8 @@ use crate::io::{
     self, BorrowedBuf, BufReader, BufWriter, ErrorKind, IoSlice, LineWriter, SeekFrom,
 };
 use crate::mem::MaybeUninit;
-use crate::panic;
 use crate::sync::atomic::{AtomicUsize, Ordering};
-use crate::thread;
+use crate::{panic, thread};
 
 /// A dummy reader intended at testing short-reads propagation.
 pub struct ShortReader {
diff --git a/library/std/src/io/copy/tests.rs b/library/std/src/io/copy/tests.rs
index a1f909a3c53..7e08826a7e1 100644
--- a/library/std/src/io/copy/tests.rs
+++ b/library/std/src/io/copy/tests.rs
@@ -119,13 +119,12 @@ fn copy_specializes_from_slice() {
 
 #[cfg(unix)]
 mod io_benches {
-    use crate::fs::File;
-    use crate::fs::OpenOptions;
+    use test::Bencher;
+
+    use crate::fs::{File, OpenOptions};
     use crate::io::prelude::*;
     use crate::io::BufReader;
 
-    use test::Bencher;
-
     #[bench]
     fn bench_copy_buf_reader(b: &mut Bencher) {
         let mut file_in = File::open("/dev/zero").expect("opening /dev/zero failed");
diff --git a/library/std/src/io/cursor.rs b/library/std/src/io/cursor.rs
index 2ed64a40495..9f913eae095 100644
--- a/library/std/src/io/cursor.rs
+++ b/library/std/src/io/cursor.rs
@@ -1,10 +1,9 @@
 #[cfg(test)]
 mod tests;
 
-use crate::io::prelude::*;
-
 use crate::alloc::Allocator;
 use crate::cmp;
+use crate::io::prelude::*;
 use crate::io::{self, BorrowedCursor, ErrorKind, IoSlice, IoSliceMut, SeekFrom};
 
 /// A `Cursor` wraps an in-memory buffer and provides it with a
@@ -210,55 +209,60 @@ impl<T> Cursor<T>
 where
     T: AsRef<[u8]>,
 {
-    /// Returns the remaining slice.
+    /// Splits the underlying slice at the cursor position and returns them.
     ///
     /// # Examples
     ///
     /// ```
-    /// #![feature(cursor_remaining)]
+    /// #![feature(cursor_split)]
     /// use std::io::Cursor;
     ///
     /// let mut buff = Cursor::new(vec![1, 2, 3, 4, 5]);
     ///
-    /// assert_eq!(buff.remaining_slice(), &[1, 2, 3, 4, 5]);
+    /// assert_eq!(buff.split(), ([].as_slice(), [1, 2, 3, 4, 5].as_slice()));
     ///
     /// buff.set_position(2);
-    /// assert_eq!(buff.remaining_slice(), &[3, 4, 5]);
-    ///
-    /// buff.set_position(4);
-    /// assert_eq!(buff.remaining_slice(), &[5]);
+    /// assert_eq!(buff.split(), ([1, 2].as_slice(), [3, 4, 5].as_slice()));
     ///
     /// buff.set_position(6);
-    /// assert_eq!(buff.remaining_slice(), &[]);
+    /// assert_eq!(buff.split(), ([1, 2, 3, 4, 5].as_slice(), [].as_slice()));
     /// ```
-    #[unstable(feature = "cursor_remaining", issue = "86369")]
-    pub fn remaining_slice(&self) -> &[u8] {
-        let len = self.pos.min(self.inner.as_ref().len() as u64);
-        &self.inner.as_ref()[(len as usize)..]
+    #[unstable(feature = "cursor_split", issue = "86369")]
+    pub fn split(&self) -> (&[u8], &[u8]) {
+        let slice = self.inner.as_ref();
+        let pos = self.pos.min(slice.len() as u64);
+        slice.split_at(pos as usize)
     }
+}
 
-    /// Returns `true` if the remaining slice is empty.
+impl<T> Cursor<T>
+where
+    T: AsMut<[u8]>,
+{
+    /// Splits the underlying slice at the cursor position and returns them
+    /// mutably.
     ///
     /// # Examples
     ///
     /// ```
-    /// #![feature(cursor_remaining)]
+    /// #![feature(cursor_split)]
     /// use std::io::Cursor;
     ///
     /// let mut buff = Cursor::new(vec![1, 2, 3, 4, 5]);
     ///
-    /// buff.set_position(2);
-    /// assert!(!buff.is_empty());
+    /// assert_eq!(buff.split_mut(), ([].as_mut_slice(), [1, 2, 3, 4, 5].as_mut_slice()));
     ///
-    /// buff.set_position(5);
-    /// assert!(buff.is_empty());
+    /// buff.set_position(2);
+    /// assert_eq!(buff.split_mut(), ([1, 2].as_mut_slice(), [3, 4, 5].as_mut_slice()));
     ///
-    /// buff.set_position(10);
-    /// assert!(buff.is_empty());
+    /// buff.set_position(6);
+    /// assert_eq!(buff.split_mut(), ([1, 2, 3, 4, 5].as_mut_slice(), [].as_mut_slice()));
     /// ```
-    #[unstable(feature = "cursor_remaining", issue = "86369")]
-    pub fn is_empty(&self) -> bool {
-        self.pos >= self.inner.as_ref().len() as u64
+    #[unstable(feature = "cursor_split", issue = "86369")]
+    pub fn split_mut(&mut self) -> (&mut [u8], &mut [u8]) {
+        let slice = self.inner.as_mut();
+        let pos = self.pos.min(slice.len() as u64);
+        slice.split_at_mut(pos as usize)
     }
 }
 
@@ -320,7 +324,7 @@ where
     T: AsRef<[u8]>,
 {
     fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
-        let n = Read::read(&mut self.remaining_slice(), buf)?;
+        let n = Read::read(&mut Cursor::split(self).1, buf)?;
         self.pos += n as u64;
         Ok(n)
     }
@@ -328,7 +332,7 @@ where
     fn read_buf(&mut self, mut cursor: BorrowedCursor<'_>) -> io::Result<()> {
         let prev_written = cursor.written();
 
-        Read::read_buf(&mut self.remaining_slice(), cursor.reborrow())?;
+        Read::read_buf(&mut Cursor::split(self).1, cursor.reborrow())?;
 
         self.pos += (cursor.written() - prev_written) as u64;
 
@@ -352,7 +356,7 @@ where
     }
 
     fn read_exact(&mut self, buf: &mut [u8]) -> io::Result<()> {
-        let result = Read::read_exact(&mut self.remaining_slice(), buf);
+        let result = Read::read_exact(&mut Cursor::split(self).1, buf);
 
         match result {
             Ok(_) => self.pos += buf.len() as u64,
@@ -366,14 +370,14 @@ where
     fn read_buf_exact(&mut self, mut cursor: BorrowedCursor<'_>) -> io::Result<()> {
         let prev_written = cursor.written();
 
-        let result = Read::read_buf_exact(&mut self.remaining_slice(), cursor.reborrow());
+        let result = Read::read_buf_exact(&mut Cursor::split(self).1, cursor.reborrow());
         self.pos += (cursor.written() - prev_written) as u64;
 
         result
     }
 
     fn read_to_end(&mut self, buf: &mut Vec<u8>) -> io::Result<usize> {
-        let content = self.remaining_slice();
+        let content = Cursor::split(self).1;
         let len = content.len();
         buf.try_reserve(len)?;
         buf.extend_from_slice(content);
@@ -384,7 +388,7 @@ where
 
     fn read_to_string(&mut self, buf: &mut String) -> io::Result<usize> {
         let content =
-            crate::str::from_utf8(self.remaining_slice()).map_err(|_| io::Error::INVALID_UTF8)?;
+            crate::str::from_utf8(Cursor::split(self).1).map_err(|_| io::Error::INVALID_UTF8)?;
         let len = content.len();
         buf.try_reserve(len)?;
         buf.push_str(content);
@@ -400,7 +404,7 @@ where
     T: AsRef<[u8]>,
 {
     fn fill_buf(&mut self) -> io::Result<&[u8]> {
-        Ok(self.remaining_slice())
+        Ok(Cursor::split(self).1)
     }
     fn consume(&mut self, amt: usize) {
         self.pos += amt as u64;
diff --git a/library/std/src/io/error.rs b/library/std/src/io/error.rs
index 8de27367a3f..e8ae1d99fbf 100644
--- a/library/std/src/io/error.rs
+++ b/library/std/src/io/error.rs
@@ -11,10 +11,7 @@ mod repr_unpacked;
 #[cfg(any(not(target_pointer_width = "64"), target_os = "uefi"))]
 use repr_unpacked::Repr;
 
-use crate::error;
-use crate::fmt;
-use crate::result;
-use crate::sys;
+use crate::{error, fmt, result, sys};
 
 /// A specialized [`Result`] type for I/O operations.
 ///
@@ -167,7 +164,7 @@ impl SimpleMessage {
     }
 }
 
-/// Create and return an `io::Error` for a given `ErrorKind` and constant
+/// Creates and returns an `io::Error` for a given `ErrorKind` and constant
 /// message. This doesn't allocate.
 pub(crate) macro const_io_error($kind:expr, $message:expr $(,)?) {
     $crate::io::error::Error::from_static_message({
@@ -852,7 +849,7 @@ impl Error {
         }
     }
 
-    /// Attempt to downcast the custom boxed error to `E`.
+    /// Attempts to downcast the custom boxed error to `E`.
     ///
     /// If this [`Error`] contains a custom boxed error,
     /// then it would attempt downcasting on the boxed error,
diff --git a/library/std/src/io/error/repr_bitpacked.rs b/library/std/src/io/error/repr_bitpacked.rs
index fbb74967df3..9d3ade46bd9 100644
--- a/library/std/src/io/error/repr_bitpacked.rs
+++ b/library/std/src/io/error/repr_bitpacked.rs
@@ -102,10 +102,11 @@
 //! to use a pointer type to store something that may hold an integer, some of
 //! the time.
 
-use super::{Custom, ErrorData, ErrorKind, RawOsError, SimpleMessage};
 use core::marker::PhantomData;
 use core::ptr::{self, NonNull};
 
+use super::{Custom, ErrorData, ErrorKind, RawOsError, SimpleMessage};
+
 // The 2 least-significant bits are used as tag.
 const TAG_MASK: usize = 0b11;
 const TAG_SIMPLE_MESSAGE: usize = 0b00;
diff --git a/library/std/src/io/error/tests.rs b/library/std/src/io/error/tests.rs
index fc6db2825e8..064e2e36b7a 100644
--- a/library/std/src/io/error/tests.rs
+++ b/library/std/src/io/error/tests.rs
@@ -1,10 +1,9 @@
 use super::{const_io_error, Custom, Error, ErrorData, ErrorKind, Repr, SimpleMessage};
 use crate::assert_matches::assert_matches;
-use crate::error;
-use crate::fmt;
 use crate::mem::size_of;
 use crate::sys::decode_error_kind;
 use crate::sys::os::error_string;
+use crate::{error, fmt};
 
 #[test]
 fn test_size() {
@@ -95,7 +94,8 @@ fn test_errorkind_packing() {
 
 #[test]
 fn test_simple_message_packing() {
-    use super::{ErrorKind::*, SimpleMessage};
+    use super::ErrorKind::*;
+    use super::SimpleMessage;
     macro_rules! check_simple_msg {
         ($err:expr, $kind:ident, $msg:literal) => {{
             let e = &$err;
diff --git a/library/std/src/io/impls.rs b/library/std/src/io/impls.rs
index a8a2e9413e1..85023540a81 100644
--- a/library/std/src/io/impls.rs
+++ b/library/std/src/io/impls.rs
@@ -2,12 +2,9 @@
 mod tests;
 
 use crate::alloc::Allocator;
-use crate::cmp;
 use crate::collections::VecDeque;
-use crate::fmt;
 use crate::io::{self, BorrowedCursor, BufRead, IoSlice, IoSliceMut, Read, Seek, SeekFrom, Write};
-use crate::mem;
-use crate::str;
+use crate::{cmp, fmt, mem, str};
 
 // =============================================================================
 // Forwarding implementations
diff --git a/library/std/src/io/mod.rs b/library/std/src/io/mod.rs
index 1345a30361e..644b294db8d 100644
--- a/library/std/src/io/mod.rs
+++ b/library/std/src/io/mod.rs
@@ -297,15 +297,12 @@
 #[cfg(test)]
 mod tests;
 
-use crate::cmp;
-use crate::fmt;
-use crate::mem::take;
-use crate::ops::{Deref, DerefMut};
-use crate::slice;
-use crate::str;
-use crate::sys;
+#[unstable(feature = "read_buf", issue = "78485")]
+pub use core::io::{BorrowedBuf, BorrowedCursor};
 use core::slice::memchr;
 
+pub(crate) use error::const_io_error;
+
 #[stable(feature = "bufwriter_into_parts", since = "1.56.0")]
 pub use self::buffered::WriterPanicked;
 #[unstable(feature = "raw_os_error_ty", issue = "107792")]
@@ -328,10 +325,9 @@ pub use self::{
     stdio::{stderr, stdin, stdout, Stderr, StderrLock, Stdin, StdinLock, Stdout, StdoutLock},
     util::{empty, repeat, sink, Empty, Repeat, Sink},
 };
-
-#[unstable(feature = "read_buf", issue = "78485")]
-pub use core::io::{BorrowedBuf, BorrowedCursor};
-pub(crate) use error::const_io_error;
+use crate::mem::take;
+use crate::ops::{Deref, DerefMut};
+use crate::{cmp, fmt, slice, str, sys};
 
 mod buffered;
 pub(crate) mod copy;
@@ -782,7 +778,7 @@ pub trait Read {
         false
     }
 
-    /// Read all bytes until EOF in this source, placing them into `buf`.
+    /// Reads all bytes until EOF in this source, placing them into `buf`.
     ///
     /// All bytes read from this source will be appended to the specified buffer
     /// `buf`. This function will continuously call [`read()`] to append more data to
@@ -866,7 +862,7 @@ pub trait Read {
         default_read_to_end(self, buf, None)
     }
 
-    /// Read all bytes until EOF in this source, appending them to `buf`.
+    /// Reads all bytes until EOF in this source, appending them to `buf`.
     ///
     /// If successful, this function returns the number of bytes which were read
     /// and appended to `buf`.
@@ -909,7 +905,7 @@ pub trait Read {
         default_read_to_string(self, buf, None)
     }
 
-    /// Read the exact number of bytes required to fill `buf`.
+    /// Reads the exact number of bytes required to fill `buf`.
     ///
     /// This function reads as many bytes as necessary to completely fill the
     /// specified buffer `buf`.
@@ -973,7 +969,7 @@ pub trait Read {
         default_read_buf(|b| self.read(b), buf)
     }
 
-    /// Read the exact number of bytes required to fill `cursor`.
+    /// Reads the exact number of bytes required to fill `cursor`.
     ///
     /// This is similar to the [`read_exact`](Read::read_exact) method, except
     /// that it is passed a [`BorrowedCursor`] rather than `[u8]` to allow use
@@ -1159,7 +1155,7 @@ pub trait Read {
     }
 }
 
-/// Read all bytes from a [reader][Read] into a new [`String`].
+/// Reads all bytes from a [reader][Read] into a new [`String`].
 ///
 /// This is a convenience function for [`Read::read_to_string`]. Using this
 /// function avoids having to create a variable first and provides more type
@@ -1212,7 +1208,7 @@ pub fn read_to_string<R: Read>(mut reader: R) -> Result<String> {
 
 /// A buffer type used with `Read::read_vectored`.
 ///
-/// It is semantically a wrapper around an `&mut [u8]`, but is guaranteed to be
+/// It is semantically a wrapper around a `&mut [u8]`, but is guaranteed to be
 /// ABI compatible with the `iovec` type on Unix platforms and `WSABUF` on
 /// Windows.
 #[stable(feature = "iovec", since = "1.36.0")]
@@ -1266,7 +1262,7 @@ impl<'a> IoSliceMut<'a> {
     /// buf.advance(3);
     /// assert_eq!(buf.deref(), [1; 5].as_ref());
     /// ```
-    #[stable(feature = "io_slice_advance", since = "CURRENT_RUSTC_VERSION")]
+    #[stable(feature = "io_slice_advance", since = "1.81.0")]
     #[inline]
     pub fn advance(&mut self, n: usize) {
         self.0.advance(n)
@@ -1305,7 +1301,7 @@ impl<'a> IoSliceMut<'a> {
     /// assert_eq!(bufs[0].deref(), [2; 14].as_ref());
     /// assert_eq!(bufs[1].deref(), [3; 8].as_ref());
     /// ```
-    #[stable(feature = "io_slice_advance", since = "CURRENT_RUSTC_VERSION")]
+    #[stable(feature = "io_slice_advance", since = "1.81.0")]
     #[inline]
     pub fn advance_slices(bufs: &mut &mut [IoSliceMut<'a>], n: usize) {
         // Number of buffers to remove.
@@ -1406,7 +1402,7 @@ impl<'a> IoSlice<'a> {
     /// buf.advance(3);
     /// assert_eq!(buf.deref(), [1; 5].as_ref());
     /// ```
-    #[stable(feature = "io_slice_advance", since = "CURRENT_RUSTC_VERSION")]
+    #[stable(feature = "io_slice_advance", since = "1.81.0")]
     #[inline]
     pub fn advance(&mut self, n: usize) {
         self.0.advance(n)
@@ -1444,7 +1440,7 @@ impl<'a> IoSlice<'a> {
     /// IoSlice::advance_slices(&mut bufs, 10);
     /// assert_eq!(bufs[0].deref(), [2; 14].as_ref());
     /// assert_eq!(bufs[1].deref(), [3; 8].as_ref());
-    #[stable(feature = "io_slice_advance", since = "CURRENT_RUSTC_VERSION")]
+    #[stable(feature = "io_slice_advance", since = "1.81.0")]
     #[inline]
     pub fn advance_slices(bufs: &mut &mut [IoSlice<'a>], n: usize) {
         // Number of buffers to remove.
@@ -1531,7 +1527,7 @@ impl<'a> Deref for IoSlice<'a> {
 #[doc(notable_trait)]
 #[cfg_attr(not(test), rustc_diagnostic_item = "IoWrite")]
 pub trait Write {
-    /// Write a buffer into this writer, returning how many bytes were written.
+    /// Writes a buffer into this writer, returning how many bytes were written.
     ///
     /// This function will attempt to write the entire contents of `buf`, but
     /// the entire write might not succeed, or the write may also generate an
@@ -1630,7 +1626,7 @@ pub trait Write {
         false
     }
 
-    /// Flush this output stream, ensuring that all intermediately buffered
+    /// Flushes this output stream, ensuring that all intermediately buffered
     /// contents reach their destination.
     ///
     /// # Errors
@@ -2247,7 +2243,7 @@ pub trait BufRead: Read {
     #[stable(feature = "rust1", since = "1.0.0")]
     fn consume(&mut self, amt: usize);
 
-    /// Check if the underlying `Read` has any data left to be read.
+    /// Checks if the underlying `Read` has any data left to be read.
     ///
     /// This function may fill the buffer to check for data,
     /// so this functions returns `Result<bool>`, not `bool`.
@@ -2278,7 +2274,7 @@ pub trait BufRead: Read {
         self.fill_buf().map(|b| !b.is_empty())
     }
 
-    /// Read all bytes into `buf` until the delimiter `byte` or EOF is reached.
+    /// Reads all bytes into `buf` until the delimiter `byte` or EOF is reached.
     ///
     /// This function will read bytes from the underlying stream until the
     /// delimiter or EOF is found. Once found, all bytes up to, and including,
@@ -2337,7 +2333,7 @@ pub trait BufRead: Read {
         read_until(self, byte, buf)
     }
 
-    /// Skip all bytes until the delimiter `byte` or EOF is reached.
+    /// Skips all bytes until the delimiter `byte` or EOF is reached.
     ///
     /// This function will read (and discard) bytes from the underlying stream until the
     /// delimiter or EOF is found.
@@ -2399,7 +2395,7 @@ pub trait BufRead: Read {
         skip_until(self, byte)
     }
 
-    /// Read all bytes until a newline (the `0xA` byte) is reached, and append
+    /// Reads all bytes until a newline (the `0xA` byte) is reached, and append
     /// them to the provided `String` buffer.
     ///
     /// Previous content of the buffer will be preserved. To avoid appending to
@@ -3038,7 +3034,7 @@ where
     }
 }
 
-/// Read a single byte in a slow, generic way. This is used by the default
+/// Reads 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>> {
diff --git a/library/std/src/io/stdio.rs b/library/std/src/io/stdio.rs
index 9aee2bb5e1c..6de069a518e 100644
--- a/library/std/src/io/stdio.rs
+++ b/library/std/src/io/stdio.rs
@@ -3,11 +3,10 @@
 #[cfg(test)]
 mod tests;
 
-use crate::io::prelude::*;
-
 use crate::cell::{Cell, RefCell};
 use crate::fmt;
 use crate::fs::File;
+use crate::io::prelude::*;
 use crate::io::{
     self, BorrowedCursor, BufReader, IoSlice, IoSliceMut, LineWriter, Lines, SpecReadByte,
 };
@@ -1092,7 +1091,7 @@ pub fn try_set_output_capture(
     OUTPUT_CAPTURE.try_with(move |slot| slot.replace(sink))
 }
 
-/// Write `args` to the capture buffer if enabled and possible, or `global_s`
+/// Writes `args` to the capture buffer if enabled and possible, or `global_s`
 /// otherwise. `label` identifies the stream in a panic message.
 ///
 /// This function is used to print error messages, so it takes extra
diff --git a/library/std/src/io/tests.rs b/library/std/src/io/tests.rs
index a2c1c430863..bb6a53bb290 100644
--- a/library/std/src/io/tests.rs
+++ b/library/std/src/io/tests.rs
@@ -1,7 +1,8 @@
 use super::{repeat, BorrowedBuf, Cursor, SeekFrom};
 use crate::cmp::{self, min};
-use crate::io::{self, IoSlice, IoSliceMut, DEFAULT_BUF_SIZE};
-use crate::io::{BufRead, BufReader, Read, Seek, Write};
+use crate::io::{
+    self, BufRead, BufReader, IoSlice, IoSliceMut, Read, Seek, Write, DEFAULT_BUF_SIZE,
+};
 use crate::mem::MaybeUninit;
 use crate::ops::Deref;
 
@@ -530,7 +531,7 @@ fn io_slice_advance_slices_beyond_total_length() {
     assert!(bufs.is_empty());
 }
 
-/// Create a new writer that reads from at most `n_bufs` and reads
+/// Creates a new writer that reads from at most `n_bufs` and reads
 /// `per_call` bytes (in total) per call to write.
 fn test_writer(n_bufs: usize, per_call: usize) -> TestWriter {
     TestWriter { n_bufs, per_call, written: Vec::new() }
@@ -675,13 +676,13 @@ fn cursor_read_exact_eof() {
 
     let mut r = slice.clone();
     assert!(r.read_exact(&mut [0; 10]).is_err());
-    assert!(r.is_empty());
+    assert!(Cursor::split(&r).1.is_empty());
 
     let mut r = slice;
     let buf = &mut [0; 10];
     let mut buf = BorrowedBuf::from(buf.as_mut_slice());
     assert!(r.read_buf_exact(buf.unfilled()).is_err());
-    assert!(r.is_empty());
+    assert!(Cursor::split(&r).1.is_empty());
     assert_eq!(buf.filled(), b"123456");
 }
 
diff --git a/library/std/src/io/util/tests.rs b/library/std/src/io/util/tests.rs
index 6de91e29c77..1dff3f3832b 100644
--- a/library/std/src/io/util/tests.rs
+++ b/library/std/src/io/util/tests.rs
@@ -1,6 +1,5 @@
 use crate::io::prelude::*;
 use crate::io::{empty, repeat, sink, BorrowedBuf, Empty, Repeat, SeekFrom, Sink};
-
 use crate::mem::MaybeUninit;
 
 #[test]