about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--library/std/src/fs.rs10
-rw-r--r--library/std/src/io/buffered/bufreader.rs15
-rw-r--r--library/std/src/io/buffered/tests.rs32
-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/impls.rs16
-rw-r--r--library/std/src/io/mod.rs83
-rw-r--r--library/std/src/io/readbuf.rs243
-rw-r--r--library/std/src/io/readbuf/tests.rs172
-rw-r--r--library/std/src/io/tests.rs20
-rw-r--r--library/std/src/io/util.rs14
-rw-r--r--library/std/src/io/util/tests.rs48
-rw-r--r--library/std/src/sys/unix/fd.rs11
-rw-r--r--library/std/src/sys/unix/fs.rs6
14 files changed, 324 insertions, 390 deletions
diff --git a/library/std/src/fs.rs b/library/std/src/fs.rs
index c8e131b6ee1..d41f32b5b3f 100644
--- a/library/std/src/fs.rs
+++ b/library/std/src/fs.rs
@@ -13,7 +13,7 @@ mod tests;
 
 use crate::ffi::OsString;
 use crate::fmt;
-use crate::io::{self, IoSlice, IoSliceMut, Read, ReadBuf, Seek, SeekFrom, Write};
+use crate::io::{self, BorrowCursor, IoSlice, IoSliceMut, Read, Seek, SeekFrom, Write};
 use crate::path::{Path, PathBuf};
 use crate::sys::fs as fs_imp;
 use crate::sys_common::{AsInner, AsInnerMut, FromInner, IntoInner};
@@ -703,8 +703,8 @@ impl Read for File {
         self.inner.read_vectored(bufs)
     }
 
-    fn read_buf(&mut self, buf: &mut ReadBuf<'_>) -> io::Result<()> {
-        self.inner.read_buf(buf)
+    fn read_buf(&mut self, cursor: BorrowCursor<'_, '_>) -> io::Result<()> {
+        self.inner.read_buf(cursor)
     }
 
     #[inline]
@@ -755,8 +755,8 @@ impl Read for &File {
         self.inner.read(buf)
     }
 
-    fn read_buf(&mut self, buf: &mut ReadBuf<'_>) -> io::Result<()> {
-        self.inner.read_buf(buf)
+    fn read_buf(&mut self, cursor: BorrowCursor<'_, '_>) -> io::Result<()> {
+        self.inner.read_buf(cursor)
     }
 
     fn read_vectored(&mut self, bufs: &mut [IoSliceMut<'_>]) -> io::Result<usize> {
diff --git a/library/std/src/io/buffered/bufreader.rs b/library/std/src/io/buffered/bufreader.rs
index f7fbaa9c276..1f19ac11bf1 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, BufRead, IoSliceMut, Read, ReadBuf, Seek, SeekFrom, SizeHint, DEFAULT_BUF_SIZE,
+    self, BorrowBuf, BorrowCursor, BufRead, IoSliceMut, Read, Seek, SeekFrom, SizeHint,
+    DEFAULT_BUF_SIZE,
 };
 use buffer::Buffer;
 
@@ -266,21 +267,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: BorrowCursor<'_, '_>) -> 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.clone())?;
 
-        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/tests.rs b/library/std/src/io/buffered/tests.rs
index fe45b132638..c93b69bf1f7 100644
--- a/library/std/src/io/buffered/tests.rs
+++ b/library/std/src/io/buffered/tests.rs
@@ -1,5 +1,5 @@
 use crate::io::prelude::*;
-use crate::io::{self, BufReader, BufWriter, ErrorKind, IoSlice, LineWriter, ReadBuf, SeekFrom};
+use crate::io::{self, BorrowBuf, BufReader, BufWriter, ErrorKind, IoSlice, LineWriter, SeekFrom};
 use crate::mem::MaybeUninit;
 use crate::panic;
 use crate::sync::atomic::{AtomicUsize, Ordering};
@@ -61,48 +61,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: BorrowBuf<'_> = 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: BorrowBuf<'_> = 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: BorrowBuf<'_> = 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: BorrowBuf<'_> = 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]
diff --git a/library/std/src/io/copy.rs b/library/std/src/io/copy.rs
index 1a10245e4a5..193bcd47467 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::{BorrowBuf, 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: BorrowBuf<'_> = 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.clone()) {
                     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: BorrowBuf 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: BorrowBuf<'_> = 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 f3fbfc44789..460b1504ffb 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, BorrowCursor, 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: BorrowCursor<'_, '_>) -> io::Result<()> {
+        let prev_written = cursor.written();
 
-        Read::read_buf(&mut self.fill_buf()?, buf)?;
+        Read::read_buf(&mut self.fill_buf()?, cursor.clone())?;
 
-        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/impls.rs b/library/std/src/io/impls.rs
index 95072547302..eee5ab6ec10 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, BorrowCursor, 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: BorrowCursor<'_, '_>) -> 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: BorrowCursor<'_, '_>) -> 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: BorrowCursor<'_, '_>) -> 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(())
diff --git a/library/std/src/io/mod.rs b/library/std/src/io/mod.rs
index 96addbd1a05..b3218b2831d 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::{BorrowBuf, BorrowCursor};
 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: BorrowBuf<'_> = 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.clone()) {
             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: BorrowBuf'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: BorrowCursor<'_, '_>) -> 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(())
 }
 
@@ -801,32 +805,33 @@ pub trait Read {
         default_read_exact(self, buf)
     }
 
+    // TODO naming, if should the method be read_cursor? Or should we change the names of the data structures?
     /// 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 [`BorrowCursor`] 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: BorrowCursor<'_, '_>) -> 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 [`BorrowCursor`] 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: BorrowCursor<'_, '_>) -> Result<()> {
+        while cursor.capacity() > 0 {
+            let prev_written = cursor.written();
+            match self.read_buf(cursor.clone()) {
                 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"));
             }
         }
@@ -2582,50 +2587,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: BorrowCursor<'_, '_>) -> 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: BorrowBuf<'_> = 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.clone())?;
 
-            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.clone())?;
+            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 78d1113f837..4578433b22a 100644
--- a/library/std/src/io/readbuf.rs
+++ b/library/std/src/io/readbuf.rs
@@ -7,6 +7,7 @@ use crate::cmp;
 use crate::fmt::{self, Debug, Formatter};
 use crate::mem::MaybeUninit;
 
+// TODO docs
 /// A wrapper around a byte buffer that 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
@@ -20,50 +21,66 @@ use crate::mem::MaybeUninit;
 /// [ filled |         unfilled         ]
 /// [    initialized    | uninitialized ]
 /// ```
-pub struct ReadBuf<'a> {
+pub struct BorrowBuf<'a> {
     buf: &'a mut [MaybeUninit<u8>],
     filled: usize,
     initialized: usize,
 }
 
-impl Debug for ReadBuf<'_> {
+impl Debug for BorrowBuf<'_> {
     fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
         f.debug_struct("ReadBuf")
-            .field("init", &self.initialized())
+            .field("init", &self.initialized)
             .field("filled", &self.filled)
             .field("capacity", &self.capacity())
             .finish()
     }
 }
 
-impl<'a> ReadBuf<'a> {
-    /// Creates a new `ReadBuf` from a fully initialized buffer.
+/// Creates a new `BorrowBuf` from a fully initialized slice.
+impl<'a> From<&'a mut [u8]> for BorrowBuf<'a> {
     #[inline]
-    pub fn new(buf: &'a mut [u8]) -> ReadBuf<'a> {
-        let len = buf.len();
+    fn from(slice: &'a mut [u8]) -> BorrowBuf<'a> {
+        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() },
+        BorrowBuf {
+            //SAFETY: initialized data never becoming uninitialized is an invariant of BorrowBuf
+            buf: unsafe { (slice as *mut [u8]).as_uninit_slice_mut().unwrap() },
             filled: 0,
             initialized: len,
         }
     }
+}
 
-    /// Creates a new `ReadBuf` from a fully uninitialized buffer.
-    ///
-    /// Use `assume_init` if part of the buffer is known to be already initialized.
+/// Creates a new `BorrowBuf` from a fully uninitialized buffer.
+///
+/// Use `set_init` if part of the buffer is known to be already initialized.
+impl<'a> From<&'a mut [MaybeUninit<u8>]> for BorrowBuf<'a> {
     #[inline]
-    pub fn uninit(buf: &'a mut [MaybeUninit<u8>]) -> ReadBuf<'a> {
-        ReadBuf { buf, filled: 0, initialized: 0 }
+    fn from(buf: &'a mut [MaybeUninit<u8>]) -> BorrowBuf<'a> {
+        BorrowBuf { buf, filled: 0, initialized: 0 }
     }
+}
 
+impl<'a> BorrowBuf<'a> {
     /// 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.initialized
+    }
+
     /// Returns a shared reference to the filled portion of the buffer.
     #[inline]
     pub fn filled(&self) -> &[u8] {
@@ -71,179 +88,157 @@ impl<'a> ReadBuf<'a> {
         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<'b>(&'b mut self) -> BorrowCursor<'a, 'b> {
+        BorrowCursor { start: self.filled, buf: 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.
+    /// `BorrowBuf` 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.initialized = cmp::max(self.initialized, n);
+        self
     }
+}
 
-    /// Returns a mutable reference to the uninitialized part of the buffer.
-    ///
-    /// It is safe to uninitialize any of these bytes.
+/// A cursor view of a [`BorrowBuf`](BorrowBuf).
+///
+/// Provides mutable access to the unfilled portion (both initialised and uninitialised data) from
+/// the buffer.
+#[derive(Debug)]
+pub struct BorrowCursor<'a, 'b> {
+    buf: &'b mut BorrowBuf<'a>,
+    start: usize,
+}
+
+impl<'a, 'b> BorrowCursor<'a, 'b> {
+    /// Clone this cursor.
     #[inline]
-    pub fn uninitialized_mut(&mut self) -> &mut [MaybeUninit<u8>] {
-        &mut self.buf[self.initialized..]
+    pub fn clone<'c>(&'c mut self) -> BorrowCursor<'a, 'c> {
+        BorrowCursor { buf: 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
-    ///
-    /// Panics if `self.remaining()` is less than `n`.
+    /// Returns the number of bytes written to this cursor.
+    // TODO check for reuse uses
     #[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);
-            }
+    pub fn written(&self) -> usize {
+        self.buf.filled - self.start
+    }
 
-            // SAFETY: we just initialized uninit bytes, and the previous bytes were already init
-            unsafe {
-                self.assume_init(n);
-            }
+    /// Returns a shared reference to the initialized portion of the buffer.
+    #[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.initialized])
         }
-
-        let filled = self.filled;
-
-        &mut self.initialized_mut()[filled..filled + n]
     }
 
-    /// 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 buffer.
     #[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.initialized],
+            )
+        }
     }
 
-    /// Clears the buffer, resetting the filled region to empty.
+    /// Returns a mutable reference to the uninitialized part of the buffer.
     ///
-    /// 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.initialized..]
+    }
+
+    /// A view of the cursor as a mutable slice of `MaybeUninit<u8>`.
+    #[inline]
+    pub unsafe fn as_mut(&mut self) -> &mut [MaybeUninit<u8>] {
+        &mut self.buf.buf[self.buf.filled..]
     }
 
     /// Increases the size of the filled region of the buffer.
     ///
-    /// The number of initialized bytes is not changed.
-    ///
-    /// # 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` elements of the cursor have been properly
+    /// initialised.
     #[inline]
-    pub fn add_filled(&mut self, n: usize) -> &mut Self {
-        self.set_filled(self.filled + n)
+    pub unsafe fn advance(&mut self, n: usize) -> &mut Self {
+        self.buf.filled += n;
+        self.buf.initialized = cmp::max(self.buf.initialized, self.buf.filled);
+        self
     }
 
-    /// Sets the size of the filled region of the buffer.
-    ///
-    /// The number of initialized bytes is not changed.
-    ///
-    /// 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
-    ///
-    /// Panics if the filled region of the buffer would become larger than the initialized region.
+    /// Initialised 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.initialized = 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
+    /// `BorrowBuf` 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.initialized = cmp::max(self.buf.initialized, 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 the 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.add_filled(buf.len());
-    }
-
-    /// Returns the amount of bytes that have been filled.
-    #[inline]
-    pub fn filled_len(&self) -> usize {
-        self.filled
-    }
 
-    /// Returns the amount of bytes that have been initialized.
-    #[inline]
-    pub fn initialized_len(&self) -> usize {
-        self.initialized
+            self.set_init(buf.len());
+        }
+        self.buf.filled += buf.len();
     }
 }
diff --git a/library/std/src/io/readbuf/tests.rs b/library/std/src/io/readbuf/tests.rs
index 3b7a5a56d22..584e5de982e 100644
--- a/library/std/src/io/readbuf/tests.rs
+++ b/library/std/src/io/readbuf/tests.rs
@@ -1,181 +1,117 @@
-use super::ReadBuf;
+use super::BorrowBuf;
 use crate::mem::MaybeUninit;
 
-/// Test that ReadBuf has the correct numbers when created with new
+/// Test that BorrowBuf 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: BorrowBuf<'_> = 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 BorrowBuf 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: BorrowBuf<'_> = 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: BorrowBuf<'_> = buf.into();
 
-    rbuf.initialize_unfilled();
+    rbuf.unfilled().ensure_init();
 
-    assert_eq!(rbuf.initialized_len(), 16);
-}
-
-#[test]
-fn initialize_unfilled_to() {
-    let mut buf = [MaybeUninit::uninit(); 16];
-    let mut rbuf = ReadBuf::uninit(&mut buf);
-
-    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);
+    assert_eq!(rbuf.init_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);
-}
+    let buf: &mut [_] = &mut [0; 16];
+    let mut rbuf: BorrowBuf<'_> = buf.into();
 
-#[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: BorrowBuf<'_> = 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: BorrowBuf<'_> = 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: BorrowBuf<'_> = 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);
-
-    rbuf.add_filled(8);
-
-    let filled = rbuf.filled().to_vec();
-
-    assert_eq!(&*filled, &*rbuf.filled_mut());
-}
diff --git a/library/std/src/io/tests.rs b/library/std/src/io/tests.rs
index f357f33ec52..a1322a18565 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, BorrowBuf, Cursor, SeekFrom};
 use crate::cmp::{self, min};
 use crate::io::{self, IoSlice, IoSliceMut};
 use crate::io::{BufRead, BufReader, Read, Seek, Write};
@@ -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: BorrowBuf<'_> = 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]
@@ -614,10 +614,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: BorrowBuf<'_> = 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 c1300cd67c0..5149926fd51 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, BorrowCursor, 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: BorrowCursor<'_, '_>) -> 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: BorrowCursor<'_, '_>) -> 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 08972a59a83..025173c3f44 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, BorrowBuf, 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: BorrowBuf<'_> = 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: BorrowBuf<'_> = 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: BorrowBuf<'_> = 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: BorrowBuf<'_> = buf.into();
+    e.by_ref().read_buf(buf.unfilled()).unwrap();
+    assert_eq!(buf.len(), 0);
+    assert_eq!(buf.init_len(), 0);
 }
 
 #[test]
diff --git a/library/std/src/sys/unix/fd.rs b/library/std/src/sys/unix/fd.rs
index 30812dabb4e..6adb734fb0a 100644
--- a/library/std/src/sys/unix/fd.rs
+++ b/library/std/src/sys/unix/fd.rs
@@ -4,7 +4,7 @@
 mod tests;
 
 use crate::cmp;
-use crate::io::{self, IoSlice, IoSliceMut, Read, ReadBuf};
+use crate::io::{self, BorrowCursor, IoSlice, IoSliceMut, Read};
 use crate::os::unix::io::{AsFd, AsRawFd, BorrowedFd, FromRawFd, IntoRawFd, OwnedFd, RawFd};
 use crate::sys::cvt;
 use crate::sys_common::{AsInner, FromInner, IntoInner};
@@ -131,20 +131,19 @@ impl FileDesc {
         }
     }
 
-    pub fn read_buf(&self, buf: &mut ReadBuf<'_>) -> io::Result<()> {
+    pub fn read_buf(&self, mut cursor: BorrowCursor<'_, '_>) -> io::Result<()> {
         let ret = cvt(unsafe {
             libc::read(
                 self.as_raw_fd(),
-                buf.unfilled_mut().as_mut_ptr() as *mut libc::c_void,
-                cmp::min(buf.remaining(), READ_LIMIT),
+                cursor.as_mut().as_mut_ptr() as *mut libc::c_void,
+                cmp::min(cursor.capacity(), READ_LIMIT),
             )
         })?;
 
         // Safety: `ret` bytes were written to the initialized portion of the buffer
         unsafe {
-            buf.assume_init(ret as usize);
+            cursor.advance(ret as usize);
         }
-        buf.add_filled(ret as usize);
         Ok(())
     }
 
diff --git a/library/std/src/sys/unix/fs.rs b/library/std/src/sys/unix/fs.rs
index b5cc8038ca4..374f9f72d6d 100644
--- a/library/std/src/sys/unix/fs.rs
+++ b/library/std/src/sys/unix/fs.rs
@@ -2,7 +2,7 @@ use crate::os::unix::prelude::*;
 
 use crate::ffi::{CStr, CString, OsStr, OsString};
 use crate::fmt;
-use crate::io::{self, Error, IoSlice, IoSliceMut, ReadBuf, SeekFrom};
+use crate::io::{self, BorrowCursor, Error, IoSlice, IoSliceMut, SeekFrom};
 use crate::mem;
 use crate::os::unix::io::{AsFd, AsRawFd, BorrowedFd, FromRawFd, IntoRawFd};
 use crate::path::{Path, PathBuf};
@@ -1031,8 +1031,8 @@ impl File {
         self.0.read_at(buf, offset)
     }
 
-    pub fn read_buf(&self, buf: &mut ReadBuf<'_>) -> io::Result<()> {
-        self.0.read_buf(buf)
+    pub fn read_buf(&self, cursor: BorrowCursor<'_, '_>) -> io::Result<()> {
+        self.0.read_buf(cursor)
     }
 
     pub fn write(&self, buf: &[u8]) -> io::Result<usize> {