diff --git a/std/src/fs.rs b/std/src/fs.rs index 98aa40db3..e1ab06b0d 100644 --- a/std/src/fs.rs +++ b/std/src/fs.rs @@ -703,7 +703,7 @@ impl Read for File { self.inner.read_vectored(bufs) } - fn read_buf(&mut self, cursor: BorrowedCursor<'_, '_>) -> io::Result<()> { + fn read_buf(&mut self, cursor: BorrowedCursor<'_>) -> io::Result<()> { self.inner.read_buf(cursor) } @@ -755,7 +755,7 @@ impl Read for &File { self.inner.read(buf) } - fn read_buf(&mut self, cursor: BorrowedCursor<'_, '_>) -> io::Result<()> { + fn read_buf(&mut self, cursor: BorrowedCursor<'_>) -> io::Result<()> { self.inner.read_buf(cursor) } diff --git a/std/src/io/buffered/bufreader.rs b/std/src/io/buffered/bufreader.rs index dced922ea..88ad92d8a 100644 --- a/std/src/io/buffered/bufreader.rs +++ b/std/src/io/buffered/bufreader.rs @@ -266,7 +266,7 @@ impl Read for BufReader { Ok(nread) } - fn read_buf(&mut self, mut cursor: BorrowedCursor<'_, '_>) -> io::Result<()> { + fn read_buf(&mut self, mut cursor: BorrowedCursor<'_>) -> io::Result<()> { // If we don't have any buffered data and we're doing a massive read // (larger than our internal buffer), bypass our internal buffer // entirely. @@ -278,7 +278,7 @@ impl Read for BufReader { let prev = cursor.written(); let mut rem = self.fill_buf()?; - rem.read_buf(cursor.clone())?; + rem.read_buf(cursor.reborrow())?; self.consume(cursor.written() - prev); //slice impl of read_buf known to never unfill buf diff --git a/std/src/io/buffered/bufreader/buffer.rs b/std/src/io/buffered/bufreader/buffer.rs index b122a6c0c..867c22c60 100644 --- a/std/src/io/buffered/bufreader/buffer.rs +++ b/std/src/io/buffered/bufreader/buffer.rs @@ -93,7 +93,7 @@ impl Buffer { if self.pos >= self.filled { debug_assert!(self.pos == self.filled); - let mut buf: BorrowedBuf<'_> = (&mut *self.buf).into(); + let mut buf = BorrowedBuf::from(&mut *self.buf); // SAFETY: `self.filled` bytes will always have been initialized. unsafe { buf.set_init(self.filled); diff --git a/std/src/io/copy.rs b/std/src/io/copy.rs index 1efd98b92..38b98afff 100644 --- a/std/src/io/copy.rs +++ b/std/src/io/copy.rs @@ -106,7 +106,7 @@ impl BufferedCopySpec for BufWriter { if read_buf.capacity() >= DEFAULT_BUF_SIZE { let mut cursor = read_buf.unfilled(); - match reader.read_buf(cursor.clone()) { + match reader.read_buf(cursor.reborrow()) { Ok(()) => { let bytes_read = cursor.written(); diff --git a/std/src/io/cursor.rs b/std/src/io/cursor.rs index e00577b51..d98ab021c 100644 --- a/std/src/io/cursor.rs +++ b/std/src/io/cursor.rs @@ -323,10 +323,10 @@ where Ok(n) } - fn read_buf(&mut self, mut cursor: BorrowedCursor<'_, '_>) -> io::Result<()> { + fn read_buf(&mut self, mut cursor: BorrowedCursor<'_>) -> io::Result<()> { let prev_written = cursor.written(); - Read::read_buf(&mut self.fill_buf()?, cursor.clone())?; + Read::read_buf(&mut self.fill_buf()?, cursor.reborrow())?; self.pos += (cursor.written() - prev_written) as u64; diff --git a/std/src/io/impls.rs b/std/src/io/impls.rs index 183c8c660..e5048dcc8 100644 --- a/std/src/io/impls.rs +++ b/std/src/io/impls.rs @@ -21,7 +21,7 @@ impl Read for &mut R { } #[inline] - fn read_buf(&mut self, cursor: BorrowedCursor<'_, '_>) -> io::Result<()> { + fn read_buf(&mut self, cursor: BorrowedCursor<'_>) -> io::Result<()> { (**self).read_buf(cursor) } @@ -125,7 +125,7 @@ impl Read for Box { } #[inline] - fn read_buf(&mut self, cursor: BorrowedCursor<'_, '_>) -> io::Result<()> { + fn read_buf(&mut self, cursor: BorrowedCursor<'_>) -> io::Result<()> { (**self).read_buf(cursor) } @@ -249,7 +249,7 @@ impl Read for &[u8] { } #[inline] - fn read_buf(&mut self, mut cursor: BorrowedCursor<'_, '_>) -> io::Result<()> { + fn read_buf(&mut self, mut cursor: BorrowedCursor<'_>) -> io::Result<()> { let amt = cmp::min(cursor.capacity(), self.len()); let (a, b) = self.split_at(amt); @@ -427,7 +427,7 @@ impl Read for VecDeque { } #[inline] - fn read_buf(&mut self, cursor: BorrowedCursor<'_, '_>) -> io::Result<()> { + fn read_buf(&mut self, cursor: BorrowedCursor<'_>) -> io::Result<()> { let (ref mut front, _) = self.as_slices(); let n = cmp::min(cursor.capacity(), front.len()); Read::read_buf(front, cursor)?; diff --git a/std/src/io/mod.rs b/std/src/io/mod.rs index 02f82a7e9..8b8ec32bf 100644 --- a/std/src/io/mod.rs +++ b/std/src/io/mod.rs @@ -370,7 +370,7 @@ pub(crate) fn default_read_to_end(r: &mut R, buf: &mut Vec } let mut cursor = read_buf.unfilled(); - match r.read_buf(cursor.clone()) { + match r.read_buf(cursor.reborrow()) { Ok(()) => {} Err(e) if e.kind() == ErrorKind::Interrupted => continue, Err(e) => return Err(e), @@ -462,7 +462,7 @@ pub(crate) fn default_read_exact(this: &mut R, mut buf: &mut [ } } -pub(crate) fn default_read_buf(read: F, mut cursor: BorrowedCursor<'_, '_>) -> Result<()> +pub(crate) fn default_read_buf(read: F, mut cursor: BorrowedCursor<'_>) -> Result<()> where F: FnOnce(&mut [u8]) -> Result, { @@ -812,7 +812,7 @@ pub trait Read { /// /// The default implementation delegates to `read`. #[unstable(feature = "read_buf", issue = "78485")] - fn read_buf(&mut self, buf: BorrowedCursor<'_, '_>) -> Result<()> { + fn read_buf(&mut self, buf: BorrowedCursor<'_>) -> Result<()> { default_read_buf(|b| self.read(b), buf) } @@ -821,10 +821,10 @@ pub trait Read { /// This is equivalent to the [`read_exact`](Read::read_exact) method, except that it is passed a [`BorrowedCursor`] rather than `[u8]` to /// allow use with uninitialized buffers. #[unstable(feature = "read_buf", issue = "78485")] - fn read_buf_exact(&mut self, mut cursor: BorrowedCursor<'_, '_>) -> Result<()> { + fn read_buf_exact(&mut self, mut cursor: BorrowedCursor<'_>) -> Result<()> { while cursor.capacity() > 0 { let prev_written = cursor.written(); - match self.read_buf(cursor.clone()) { + match self.read_buf(cursor.reborrow()) { Ok(()) => {} Err(e) if e.kind() == ErrorKind::Interrupted => continue, Err(e) => return Err(e), @@ -2586,7 +2586,7 @@ impl Read for Take { Ok(n) } - fn read_buf(&mut self, mut buf: BorrowedCursor<'_, '_>) -> Result<()> { + fn read_buf(&mut self, mut buf: BorrowedCursor<'_>) -> Result<()> { // Don't call into inner reader at all at EOF because it may still block if self.limit == 0 { return Ok(()); @@ -2609,7 +2609,7 @@ impl Read for Take { } let mut cursor = sliced_buf.unfilled(); - self.inner.read_buf(cursor.clone())?; + self.inner.read_buf(cursor.reborrow())?; let new_init = cursor.init_ref().len(); let filled = sliced_buf.len(); @@ -2626,7 +2626,7 @@ impl Read for Take { self.limit -= filled as u64; } else { let written = buf.written(); - self.inner.read_buf(buf.clone())?; + self.inner.read_buf(buf.reborrow())?; self.limit -= (buf.written() - written) as u64; } diff --git a/std/src/io/readbuf.rs b/std/src/io/readbuf.rs index ae3fbcc6a..b1a84095f 100644 --- a/std/src/io/readbuf.rs +++ b/std/src/io/readbuf.rs @@ -6,7 +6,7 @@ mod tests; use crate::cmp; use crate::fmt::{self, Debug, Formatter}; use crate::io::{Result, Write}; -use crate::mem::MaybeUninit; +use crate::mem::{self, MaybeUninit}; /// A borrowed byte buffer which is incrementally filled and initialized. /// @@ -23,9 +23,9 @@ use crate::mem::MaybeUninit; /// ``` /// /// 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 otherwise -/// is read-only. 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 like a +/// (`&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. @@ -55,7 +55,7 @@ impl<'data> From<&'data mut [u8]> for BorrowedBuf<'data> { let len = slice.len(); BorrowedBuf { - //SAFETY: initialized data never becoming uninitialized is an invariant of 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, @@ -95,14 +95,21 @@ impl<'data> BorrowedBuf<'data> { /// Returns a shared reference to the filled portion of the buffer. #[inline] pub fn filled(&self) -> &[u8] { - //SAFETY: We only slice the filled part of the buffer, which is always valid + // SAFETY: We only slice the filled part of the buffer, which is always valid unsafe { MaybeUninit::slice_assume_init_ref(&self.buf[0..self.filled]) } } /// Returns a cursor over the unfilled part of the buffer. #[inline] - pub fn unfilled<'this>(&'this mut self) -> BorrowedCursor<'this, 'data> { - BorrowedCursor { start: self.filled, buf: self } + 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. @@ -141,25 +148,37 @@ impl<'data> BorrowedBuf<'data> { /// `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 `'buf` lifetime is a bound on the lifetime of the underlying buffer. `'data` is a bound on -/// that buffer's underlying data. +/// 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<'buf, 'data> { +pub struct BorrowedCursor<'a> { /// The underlying buffer. - buf: &'buf mut BorrowedBuf<'data>, + // 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<'buf, 'data> BorrowedCursor<'buf, 'data> { - /// Clone this cursor. +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 cloned cursor is not - /// accessible while the clone is alive. + /// Since a cursor maintains unique access to its underlying buffer, the borrowed cursor is + /// not accessible while the new cursor exists. #[inline] - pub fn clone<'this>(&'this mut self) -> BorrowedCursor<'this, 'data> { - BorrowedCursor { buf: self.buf, start: self.start } + 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. @@ -170,8 +189,8 @@ impl<'buf, 'data> BorrowedCursor<'buf, 'data> { /// Returns the number of bytes written to this cursor since it was created from a `BorrowedBuf`. /// - /// Note that if this cursor is a clone of another, then the count returned is the count written - /// via either cursor, not the count since the cursor was cloned. + /// 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 @@ -180,14 +199,14 @@ impl<'buf, 'data> BorrowedCursor<'buf, 'data> { /// 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 + // 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 + // 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]) } @@ -275,7 +294,7 @@ impl<'buf, 'data> BorrowedCursor<'buf, 'data> { } } -impl<'buf, 'data> Write for BorrowedCursor<'buf, 'data> { +impl<'a> Write for BorrowedCursor<'a> { fn write(&mut self, buf: &[u8]) -> Result { self.append(buf); Ok(buf.len()) diff --git a/std/src/io/readbuf/tests.rs b/std/src/io/readbuf/tests.rs index 8037a9579..cc1b423f2 100644 --- a/std/src/io/readbuf/tests.rs +++ b/std/src/io/readbuf/tests.rs @@ -117,14 +117,14 @@ fn append() { } #[test] -fn clone_written() { +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.clone(); + let mut cursor2 = cursor.reborrow(); cursor2.append(&[2; 16]); assert_eq!(cursor2.written(), 32); diff --git a/std/src/io/util.rs b/std/src/io/util.rs index 7475d7111..f076ee092 100644 --- a/std/src/io/util.rs +++ b/std/src/io/util.rs @@ -47,7 +47,7 @@ impl Read for Empty { } #[inline] - fn read_buf(&mut self, _cursor: BorrowedCursor<'_, '_>) -> io::Result<()> { + fn read_buf(&mut self, _cursor: BorrowedCursor<'_>) -> io::Result<()> { Ok(()) } } @@ -130,7 +130,7 @@ impl Read for Repeat { Ok(buf.len()) } - fn read_buf(&mut self, mut buf: BorrowedCursor<'_, '_>) -> io::Result<()> { + fn read_buf(&mut self, mut buf: BorrowedCursor<'_>) -> io::Result<()> { // SAFETY: No uninit bytes are being written for slot in unsafe { buf.as_mut() } { slot.write(self.byte); diff --git a/std/src/sys/hermit/fs.rs b/std/src/sys/hermit/fs.rs index 51321c519..1c5efa94b 100644 --- a/std/src/sys/hermit/fs.rs +++ b/std/src/sys/hermit/fs.rs @@ -312,7 +312,7 @@ impl File { false } - pub fn read_buf(&self, cursor: BorrowedCursor<'_, '_>) -> io::Result<()> { + pub fn read_buf(&self, cursor: BorrowedCursor<'_>) -> io::Result<()> { crate::io::default_read_buf(|buf| self.read(buf), cursor) } diff --git a/std/src/sys/solid/fs.rs b/std/src/sys/solid/fs.rs index 0848d3d8f..8e23a7c7d 100644 --- a/std/src/sys/solid/fs.rs +++ b/std/src/sys/solid/fs.rs @@ -358,7 +358,7 @@ impl File { } } - pub fn read_buf(&self, mut cursor: BorrowedCursor<'_, '_>) -> io::Result<()> { + pub fn read_buf(&self, mut cursor: BorrowedCursor<'_>) -> io::Result<()> { unsafe { let len = cursor.capacity(); let mut out_num_bytes = MaybeUninit::uninit(); diff --git a/std/src/sys/unix/fd.rs b/std/src/sys/unix/fd.rs index 76a269bb9..dbaa3c33e 100644 --- a/std/src/sys/unix/fd.rs +++ b/std/src/sys/unix/fd.rs @@ -131,7 +131,7 @@ impl FileDesc { } } - pub fn read_buf(&self, mut cursor: BorrowedCursor<'_, '_>) -> io::Result<()> { + pub fn read_buf(&self, mut cursor: BorrowedCursor<'_>) -> io::Result<()> { let ret = cvt(unsafe { libc::read( self.as_raw_fd(), diff --git a/std/src/sys/unix/fs.rs b/std/src/sys/unix/fs.rs index 505613454..b8fc2e8da 100644 --- a/std/src/sys/unix/fs.rs +++ b/std/src/sys/unix/fs.rs @@ -1031,7 +1031,7 @@ impl File { self.0.read_at(buf, offset) } - pub fn read_buf(&self, cursor: BorrowedCursor<'_, '_>) -> io::Result<()> { + pub fn read_buf(&self, cursor: BorrowedCursor<'_>) -> io::Result<()> { self.0.read_buf(cursor) } diff --git a/std/src/sys/unsupported/fs.rs b/std/src/sys/unsupported/fs.rs index 41e39ce27..6ac1b5d2b 100644 --- a/std/src/sys/unsupported/fs.rs +++ b/std/src/sys/unsupported/fs.rs @@ -214,7 +214,7 @@ impl File { self.0 } - pub fn read_buf(&self, _cursor: BorrowedCursor<'_, '_>) -> io::Result<()> { + pub fn read_buf(&self, _cursor: BorrowedCursor<'_>) -> io::Result<()> { self.0 } diff --git a/std/src/sys/wasi/fs.rs b/std/src/sys/wasi/fs.rs index b5b5eab1a..510cf36b1 100644 --- a/std/src/sys/wasi/fs.rs +++ b/std/src/sys/wasi/fs.rs @@ -439,7 +439,7 @@ impl File { true } - pub fn read_buf(&self, cursor: BorrowedCursor<'_, '_>) -> io::Result<()> { + pub fn read_buf(&self, cursor: BorrowedCursor<'_>) -> io::Result<()> { crate::io::default_read_buf(|buf| self.read(buf), cursor) } diff --git a/std/src/sys/windows/fs.rs b/std/src/sys/windows/fs.rs index bfc2477df..9ac7cfebb 100644 --- a/std/src/sys/windows/fs.rs +++ b/std/src/sys/windows/fs.rs @@ -415,7 +415,7 @@ impl File { self.handle.read_at(buf, offset) } - pub fn read_buf(&self, cursor: BorrowedCursor<'_, '_>) -> io::Result<()> { + pub fn read_buf(&self, cursor: BorrowedCursor<'_>) -> io::Result<()> { self.handle.read_buf(cursor) } diff --git a/std/src/sys/windows/handle.rs b/std/src/sys/windows/handle.rs index 0ea6876af..ae33d48c6 100644 --- a/std/src/sys/windows/handle.rs +++ b/std/src/sys/windows/handle.rs @@ -112,7 +112,7 @@ impl Handle { } } - pub fn read_buf(&self, mut cursor: BorrowedCursor<'_, '_>) -> io::Result<()> { + pub fn read_buf(&self, mut cursor: BorrowedCursor<'_>) -> io::Result<()> { let res = unsafe { self.synchronous_read(cursor.as_mut().as_mut_ptr(), cursor.capacity(), None) };