diff --git a/core/src/array/mod.rs b/core/src/array/mod.rs index c8d0622059cde..6cca2e6358b63 100644 --- a/core/src/array/mod.rs +++ b/core/src/array/mod.rs @@ -924,7 +924,7 @@ const fn try_from_fn_erased>( /// All write accesses to this structure are unsafe and must maintain a correct /// count of `initialized` elements. /// -/// To minimize indirection fields are still pub but callers should at least use +/// To minimize indirection, fields are still pub but callers should at least use /// `push_unchecked` to signal that something unsafe is going on. struct Guard<'a, T> { /// The array to be initialized. @@ -943,7 +943,7 @@ impl Guard<'_, T> { #[rustc_const_unstable(feature = "array_try_from_fn", issue = "89379")] pub(crate) const unsafe fn push_unchecked(&mut self, item: T) { // SAFETY: If `initialized` was correct before and the caller does not - // invoke this method more than N times then writes will be in-bounds + // invoke this method more than N times, then writes will be in-bounds // and slots will not be initialized more than once. unsafe { self.array_mut.get_unchecked_mut(self.initialized).write(item); @@ -972,7 +972,7 @@ impl const Drop for Guard<'_, T> { /// `next` at most `N` times, the iterator can still be used afterwards to /// retrieve the remaining items. /// -/// If `iter.next()` panicks, all items already yielded by the iterator are +/// If `iter.next()` panics, all items already yielded by the iterator are /// dropped. /// /// Used for [`Iterator::next_chunk`]. @@ -1004,6 +1004,7 @@ fn iter_next_chunk_erased( buffer: &mut [MaybeUninit], iter: &mut impl Iterator, ) -> Result<(), usize> { + // if `Iterator::next` panics, this guard will drop already initialized items let mut guard = Guard { array_mut: buffer, initialized: 0 }; while guard.initialized < guard.array_mut.len() { let Some(item) = iter.next() else { diff --git a/core/src/io/borrowed_buf.rs b/core/src/io/borrowed_buf.rs index 088dea7812945..b765b96fd00a5 100644 --- a/core/src/io/borrowed_buf.rs +++ b/core/src/io/borrowed_buf.rs @@ -2,27 +2,26 @@ use crate::fmt::{self, Debug, Formatter}; use crate::mem::{self, MaybeUninit}; -use crate::{cmp, ptr}; -/// A borrowed byte buffer which is incrementally filled and initialized. +/// A borrowed buffer of initially uninitialized bytes, which is incrementally filled. /// -/// This type is a sort of "double cursor". It tracks three regions in the buffer: a region at the beginning of the -/// buffer that has been logically filled with data, a region that has been initialized at some point but not yet -/// logically filled, and a region at the end that is fully uninitialized. The filled region is guaranteed to be a -/// subset of the initialized region. +/// This type makes it safer to work with `MaybeUninit` buffers, such as to read into a buffer +/// without having to initialize it first. It tracks the region of bytes that have been filled and +/// the region that remains uninitialized. /// -/// In summary, the contents of the buffer can be visualized as: +/// The contents of the buffer can be visualized as: /// ```not_rust -/// [ capacity ] -/// [ filled | unfilled ] -/// [ initialized | uninitialized ] +/// [ capacity ] +/// [ len: filled and initialized | capacity - len: uninitialized ] /// ``` /// -/// A `BorrowedBuf` is created around some existing data (or capacity for data) via a unique reference -/// (`&mut`). The `BorrowedBuf` can be configured (e.g., using `clear` or `set_init`), but cannot be -/// directly written. To write into the buffer, use `unfilled` to create a `BorrowedCursor`. The cursor -/// has write-only access to the unfilled portion of the buffer (you can think of it as a -/// write-only iterator). +/// Note that `BorrowedBuf` does not distinguish between uninitialized data and data that was +/// previously initialized but no longer contains valid data. +/// +/// 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_len`), 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. /// /// The lifetime `'data` is a bound on the lifetime of the underlying data. pub struct BorrowedBuf<'data> { @@ -30,14 +29,11 @@ pub struct BorrowedBuf<'data> { buf: &'data mut [MaybeUninit], /// The length of `self.buf` which is known to be filled. filled: usize, - /// The length of `self.buf` which is known to be initialized. - init: usize, } impl Debug for BorrowedBuf<'_> { fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { f.debug_struct("BorrowedBuf") - .field("init", &self.init) .field("filled", &self.filled) .field("capacity", &self.capacity()) .finish() @@ -48,24 +44,22 @@ impl Debug for BorrowedBuf<'_> { impl<'data> From<&'data mut [u8]> for BorrowedBuf<'data> { #[inline] fn from(slice: &'data mut [u8]) -> BorrowedBuf<'data> { - let len = slice.len(); - BorrowedBuf { - // SAFETY: initialized data never becoming uninitialized is an invariant of BorrowedBuf + // SAFETY: Always in bounds. We treat the buffer as uninitialized, even though it's + // already initialized. buf: unsafe { (slice as *mut [u8]).as_uninit_slice_mut().unwrap() }, filled: 0, - init: len, } } } /// Creates a new `BorrowedBuf` from an uninitialized buffer. /// -/// Use `set_init` if part of the buffer is known to be already initialized. +/// Use `set_filled` if part of the buffer is known to be already filled. impl<'data> From<&'data mut [MaybeUninit]> for BorrowedBuf<'data> { #[inline] fn from(buf: &'data mut [MaybeUninit]) -> BorrowedBuf<'data> { - BorrowedBuf { buf, filled: 0, init: 0 } + BorrowedBuf { buf, filled: 0 } } } @@ -74,14 +68,11 @@ impl<'data> From<&'data mut [MaybeUninit]> for BorrowedBuf<'data> { /// Use `BorrowedCursor::with_unfilled_buf` instead for a safer alternative. impl<'data> From> for BorrowedBuf<'data> { #[inline] - fn from(mut buf: BorrowedCursor<'data>) -> BorrowedBuf<'data> { - let init = buf.init_mut().len(); + fn from(buf: BorrowedCursor<'data>) -> BorrowedBuf<'data> { BorrowedBuf { - // SAFETY: no initialized byte is ever uninitialized as per - // `BorrowedBuf`'s invariant + // SAFETY: Always in bounds. We treat the buffer as uninitialized. buf: unsafe { buf.buf.buf.get_unchecked_mut(buf.buf.filled..) }, filled: 0, - init, } } } @@ -99,12 +90,6 @@ impl<'data> BorrowedBuf<'data> { self.filled } - /// Returns the length of the initialized part of the buffer. - #[inline] - pub fn init_len(&self) -> usize { - self.init - } - /// Returns a shared reference to the filled portion of the buffer. #[inline] pub fn filled(&self) -> &[u8] { @@ -159,33 +144,16 @@ impl<'data> BorrowedBuf<'data> { /// Clears the buffer, resetting the filled region to empty. /// - /// The number of initialized bytes is not changed, and the contents of the buffer are not modified. + /// The contents of the buffer are not modified. #[inline] pub fn clear(&mut self) -> &mut Self { self.filled = 0; self } - - /// Asserts that the first `n` bytes of the buffer are initialized. - /// - /// `BorrowedBuf` assumes that bytes are never de-initialized, so this method does nothing when called with fewer - /// bytes than are already known to be initialized. - /// - /// # Safety - /// - /// The caller must ensure that the first `n` unfilled bytes of the buffer have already been initialized. - #[inline] - pub unsafe fn set_init(&mut self, n: usize) -> &mut Self { - self.init = cmp::max(self.init, n); - self - } } /// A writeable view of the unfilled portion of a [`BorrowedBuf`]. /// -/// The unfilled portion consists of an initialized and an uninitialized part; see [`BorrowedBuf`] -/// for details. -/// /// Data can be written directly to the cursor by using [`append`](BorrowedCursor::append) or /// indirectly by getting a slice of part or all of the cursor and writing into the slice. In the /// indirect case, the caller must call [`advance`](BorrowedCursor::advance) after writing to inform @@ -238,48 +206,17 @@ impl<'a> BorrowedCursor<'a> { self.buf.filled } - /// Returns a mutable reference to the initialized portion of the cursor. - #[inline] - pub fn init_mut(&mut self) -> &mut [u8] { - // SAFETY: We only slice the initialized part of the buffer, which is always valid - unsafe { - let buf = self.buf.buf.get_unchecked_mut(self.buf.filled..self.buf.init); - buf.assume_init_mut() - } - } - /// Returns a mutable reference to the whole cursor. /// /// # Safety /// - /// The caller must not uninitialize any bytes in the initialized portion of the cursor. + /// The caller must not uninitialize any previously initialized bytes. #[inline] pub unsafe fn as_mut(&mut self) -> &mut [MaybeUninit] { // SAFETY: always in bounds unsafe { self.buf.buf.get_unchecked_mut(self.buf.filled..) } } - /// Advances the cursor by asserting that `n` bytes have been filled. - /// - /// After advancing, the `n` bytes are no longer accessible via the cursor and can only be - /// accessed via the underlying buffer. I.e., the buffer's filled portion grows by `n` elements - /// and its unfilled portion (and the capacity of this cursor) shrinks by `n` elements. - /// - /// If less than `n` bytes initialized (by the cursor's point of view), `set_init` should be - /// called first. - /// - /// # Panics - /// - /// Panics if there are less than `n` bytes initialized. - #[inline] - pub fn advance(&mut self, n: usize) -> &mut Self { - // The subtraction cannot underflow by invariant of this type. - assert!(n <= self.buf.init - self.buf.filled); - - self.buf.filled += n; - self - } - /// Advances the cursor by asserting that `n` bytes have been filled. /// /// After advancing, the `n` bytes are no longer accessible via the cursor and can only be @@ -288,42 +225,11 @@ impl<'a> BorrowedCursor<'a> { /// /// # Safety /// - /// The caller must ensure that the first `n` bytes of the cursor have been properly - /// initialised. + /// The caller must ensure that the first `n` bytes of the cursor have been initialized. `n` + /// must not exceed the remaining capacity of this cursor. #[inline] - pub unsafe fn advance_unchecked(&mut self, n: usize) -> &mut Self { + pub unsafe fn advance(&mut self, n: usize) -> &mut Self { self.buf.filled += n; - self.buf.init = cmp::max(self.buf.init, self.buf.filled); - self - } - - /// Initializes all bytes in the cursor. - #[inline] - pub fn ensure_init(&mut self) -> &mut Self { - // SAFETY: always in bounds and we never uninitialize these bytes. - let uninit = unsafe { self.buf.buf.get_unchecked_mut(self.buf.init..) }; - - // SAFETY: 0 is a valid value for MaybeUninit and the length matches the allocation - // since it is comes from a slice reference. - unsafe { - ptr::write_bytes(uninit.as_mut_ptr(), 0, uninit.len()); - } - self.buf.init = self.buf.capacity(); - - self - } - - /// Asserts that the first `n` unfilled bytes of the cursor are initialized. - /// - /// `BorrowedBuf` assumes that bytes are never de-initialized, so this method does nothing when - /// called with fewer bytes than are already known to be initialized. - /// - /// # Safety - /// - /// The caller must ensure that the first `n` bytes of the buffer have already been initialized. - #[inline] - pub unsafe fn set_init(&mut self, n: usize) -> &mut Self { - self.buf.init = cmp::max(self.buf.init, self.buf.filled + n); self } @@ -341,10 +247,6 @@ impl<'a> BorrowedCursor<'a> { self.as_mut()[..buf.len()].write_copy_of_slice(buf); } - // SAFETY: We just added the entire contents of buf to the filled section. - unsafe { - self.set_init(buf.len()); - } self.buf.filled += buf.len(); } @@ -367,17 +269,9 @@ impl<'a> BorrowedCursor<'a> { // there, one could mark some bytes as initialized even though there aren't. assert!(core::ptr::addr_eq(prev_ptr, buf.buf)); - let filled = buf.filled; - let init = buf.init; - - // Update `init` and `filled` fields with what was written to the buffer. - // `self.buf.filled` was the starting length of the `BorrowedBuf`. - // - // SAFETY: These amounts of bytes were initialized/filled in the `BorrowedBuf`, - // and therefore they are initialized/filled in the cursor too, because the - // buffer wasn't replaced. - self.buf.init = self.buf.filled + init; - self.buf.filled += filled; + // SAFETY: These bytes were filled in the `BorrowedBuf`, so they're filled in the cursor + // too, because the buffer wasn't replaced. + self.buf.filled += buf.filled; res } diff --git a/core/src/iter/adapters/array_chunks.rs b/core/src/iter/adapters/array_chunks.rs index 967136288865c..21f46ab8b6a44 100644 --- a/core/src/iter/adapters/array_chunks.rs +++ b/core/src/iter/adapters/array_chunks.rs @@ -89,7 +89,7 @@ where match self.iter.next_chunk() { Ok(chunk) => acc = f(acc, chunk)?, Err(remainder) => { - // Make sure to not override `self.remainder` with an empty array + // Make sure to not overwrite `self.remainder` with an empty array // when `next` is called after `ArrayChunks` exhaustion. self.remainder.get_or_insert(remainder); diff --git a/core/src/iter/adapters/peekable.rs b/core/src/iter/adapters/peekable.rs index a55de75d56c6e..ee40d2b74c647 100644 --- a/core/src/iter/adapters/peekable.rs +++ b/core/src/iter/adapters/peekable.rs @@ -331,6 +331,8 @@ impl Peekable { /// If the closure panics, the next value will always be consumed and dropped /// even if the panic is caught, because the closure never returned an `Err` value to put back. /// + /// See also: [`next_if_map_mut`](Self::next_if_map_mut). + /// /// # Examples /// /// Parse the leading decimal number from an iterator of characters. @@ -419,6 +421,44 @@ impl Peekable { self.peeked = Some(unpeek); None } + + /// Gives a mutable reference to the next value of the iterator and applies a function `f` to it, + /// returning the result and advancing the iterator if `f` returns `Some`. + /// + /// Otherwise, if `f` returns `None`, the next value is kept for the next iteration. + /// + /// If `f` panics, the item that is consumed from the iterator as if `Some` was returned from `f`. + /// The value will be dropped. + /// + /// This is similar to [`next_if_map`](Self::next_if_map), except ownership of the item is not given to `f`. + /// This can be preferable if `f` would copy the item anyway. + /// + /// # Examples + /// + /// Parse the leading decimal number from an iterator of characters. + /// ``` + /// #![feature(peekable_next_if_map)] + /// let mut iter = "125 GOTO 10".chars().peekable(); + /// let mut line_num = 0_u32; + /// while let Some(digit) = iter.next_if_map_mut(|c| c.to_digit(10)) { + /// line_num = line_num * 10 + digit; + /// } + /// assert_eq!(line_num, 125); + /// assert_eq!(iter.collect::(), " GOTO 10"); + /// ``` + #[unstable(feature = "peekable_next_if_map", issue = "143702")] + pub fn next_if_map_mut(&mut self, f: impl FnOnce(&mut I::Item) -> Option) -> Option { + let unpeek = if let Some(mut item) = self.next() { + match f(&mut item) { + Some(result) => return Some(result), + None => Some(item), + } + } else { + None + }; + self.peeked = Some(unpeek); + None + } } #[unstable(feature = "trusted_len", issue = "37572")] diff --git a/core/src/mem/mod.rs b/core/src/mem/mod.rs index f4fcc9b1f3665..ad5fda0cfe4db 100644 --- a/core/src/mem/mod.rs +++ b/core/src/mem/mod.rs @@ -898,8 +898,6 @@ pub const fn replace(dest: &mut T, src: T) -> T { /// Disposes of a value. /// -/// This does so by calling the argument's implementation of [`Drop`][drop]. -/// /// This effectively does nothing for types which implement `Copy`, e.g. /// integers. Such values are copied and _then_ moved into the function, so the /// value persists after this function call. @@ -910,7 +908,7 @@ pub const fn replace(dest: &mut T, src: T) -> T { /// pub fn drop(_x: T) {} /// ``` /// -/// Because `_x` is moved into the function, it is automatically dropped before +/// Because `_x` is moved into the function, it is automatically [dropped][drop] before /// the function returns. /// /// [drop]: Drop diff --git a/core/src/slice/iter.rs b/core/src/slice/iter.rs index a2fbf6ead6461..f10b26cd71be2 100644 --- a/core/src/slice/iter.rs +++ b/core/src/slice/iter.rs @@ -1415,26 +1415,21 @@ impl<'a, T> Iterator for Windows<'a, T> { #[stable(feature = "rust1", since = "1.0.0")] impl<'a, T> DoubleEndedIterator for Windows<'a, T> { #[inline] - fn next_back(&mut self) -> Option<&'a [T]> { - if self.size.get() > self.v.len() { - None - } else { - let ret = Some(&self.v[self.v.len() - self.size.get()..]); - self.v = &self.v[..self.v.len() - 1]; - ret - } + fn next_back(&mut self) -> Option { + self.nth_back(0) } #[inline] fn nth_back(&mut self, n: usize) -> Option { - let (end, overflow) = self.v.len().overflowing_sub(n); - if end < self.size.get() || overflow { + if let Some(end) = self.v.len().checked_sub(n) + && let Some(start) = end.checked_sub(self.size.get()) + { + let res = &self.v[start..end]; + self.v = &self.v[..end - 1]; + Some(res) + } else { self.v = &self.v[..0]; // cheaper than &[] None - } else { - let ret = &self.v[end - self.size.get()..end]; - self.v = &self.v[..end - 1]; - Some(ret) } } } @@ -1523,9 +1518,7 @@ impl<'a, T> Iterator for Chunks<'a, T> { if self.v.is_empty() { (0, Some(0)) } else { - let n = self.v.len() / self.chunk_size; - let rem = self.v.len() % self.chunk_size; - let n = if rem > 0 { n + 1 } else { n }; + let n = self.v.len().div_ceil(self.chunk_size); (n, Some(n)) } } @@ -1537,13 +1530,13 @@ impl<'a, T> Iterator for Chunks<'a, T> { #[inline] fn nth(&mut self, n: usize) -> Option { - let (start, overflow) = n.overflowing_mul(self.chunk_size); - // min(len) makes a wrong start harmless, but enables optimizing this to brachless code - let chunk_start = &self.v[start.min(self.v.len())..]; - let (nth, remainder) = chunk_start.split_at(self.chunk_size.min(chunk_start.len())); - if !overflow && start < self.v.len() { - self.v = remainder; - Some(nth) + if let Some(start) = n.checked_mul(self.chunk_size) + && start < self.v.len() + { + let rest = &self.v[start..]; + let (chunk, rest) = rest.split_at(self.chunk_size.min(rest.len())); + self.v = rest; + Some(chunk) } else { self.v = &self.v[..0]; // cheaper than &[] None @@ -1608,18 +1601,15 @@ impl<'a, T> DoubleEndedIterator for Chunks<'a, T> { #[inline] fn nth_back(&mut self, n: usize) -> Option { let len = self.len(); - if n >= len { - self.v = &self.v[..0]; // cheaper than &[] - None - } else { + if n < len { let start = (len - 1 - n) * self.chunk_size; - let end = match start.checked_add(self.chunk_size) { - Some(res) => cmp::min(self.v.len(), res), - None => self.v.len(), - }; + let end = start + (self.v.len() - start).min(self.chunk_size); let nth_back = &self.v[start..end]; self.v = &self.v[..start]; Some(nth_back) + } else { + self.v = &self.v[..0]; // cheaper than &[] + None } } } @@ -1705,9 +1695,7 @@ impl<'a, T> Iterator for ChunksMut<'a, T> { if self.v.is_empty() { (0, Some(0)) } else { - let n = self.v.len() / self.chunk_size; - let rem = self.v.len() % self.chunk_size; - let n = if rem > 0 { n + 1 } else { n }; + let n = self.v.len().div_ceil(self.chunk_size); (n, Some(n)) } } @@ -1719,22 +1707,19 @@ impl<'a, T> Iterator for ChunksMut<'a, T> { #[inline] fn nth(&mut self, n: usize) -> Option<&'a mut [T]> { - let (start, overflow) = n.overflowing_mul(self.chunk_size); - if start >= self.v.len() || overflow { + if let Some(start) = n.checked_mul(self.chunk_size) + && start < self.v.len() + { + // SAFETY: `start < self.v.len()` ensures this is in bounds + let (_, rest) = unsafe { self.v.split_at_mut(start) }; + // SAFETY: `.min(rest.len()` ensures this is in bounds + let (chunk, rest) = unsafe { rest.split_at_mut(self.chunk_size.min(rest.len())) }; + self.v = rest; + // SAFETY: Nothing else points to or will point to the contents of this slice. + Some(unsafe { &mut *chunk }) + } else { self.v = &mut []; None - } else { - let end = match start.checked_add(self.chunk_size) { - Some(sum) => cmp::min(self.v.len(), sum), - None => self.v.len(), - }; - // SAFETY: The self.v contract ensures that any split_at_mut is valid. - let (head, tail) = unsafe { self.v.split_at_mut(end) }; - // SAFETY: The self.v contract ensures that any split_at_mut is valid. - let (_, nth) = unsafe { head.split_at_mut(start) }; - self.v = tail; - // SAFETY: Nothing else points to or will point to the contents of this slice. - Some(unsafe { &mut *nth }) } } @@ -1785,10 +1770,7 @@ impl<'a, T> DoubleEndedIterator for ChunksMut<'a, T> { #[inline] fn nth_back(&mut self, n: usize) -> Option { let len = self.len(); - if n >= len { - self.v = &mut []; - None - } else { + if n < len { let start = (len - 1 - n) * self.chunk_size; let end = match start.checked_add(self.chunk_size) { Some(res) => cmp::min(self.v.len(), res), @@ -1801,6 +1783,9 @@ impl<'a, T> DoubleEndedIterator for ChunksMut<'a, T> { self.v = head; // SAFETY: Nothing else points to or will point to the contents of this slice. Some(unsafe { &mut *nth_back }) + } else { + self.v = &mut []; + None } } } @@ -1909,13 +1894,10 @@ impl<'a, T> Iterator for ChunksExact<'a, T> { #[inline] fn next(&mut self) -> Option<&'a [T]> { - if self.v.len() < self.chunk_size { - None - } else { - let (fst, snd) = self.v.split_at(self.chunk_size); - self.v = snd; - Some(fst) - } + self.v.split_at_checked(self.chunk_size).and_then(|(chunk, rest)| { + self.v = rest; + Some(chunk) + }) } #[inline] @@ -1931,14 +1913,14 @@ impl<'a, T> Iterator for ChunksExact<'a, T> { #[inline] fn nth(&mut self, n: usize) -> Option { - let (start, overflow) = n.overflowing_mul(self.chunk_size); - if start >= self.v.len() || overflow { + if let Some(start) = n.checked_mul(self.chunk_size) + && start < self.v.len() + { + self.v = &self.v[start..]; + self.next() + } else { self.v = &self.v[..0]; // cheaper than &[] None - } else { - let (_, snd) = self.v.split_at(start); - self.v = snd; - self.next() } } @@ -1970,15 +1952,15 @@ impl<'a, T> DoubleEndedIterator for ChunksExact<'a, T> { #[inline] fn nth_back(&mut self, n: usize) -> Option { let len = self.len(); - if n >= len { - self.v = &self.v[..0]; // cheaper than &[] - None - } else { + if n < len { let start = (len - 1 - n) * self.chunk_size; let end = start + self.chunk_size; let nth_back = &self.v[start..end]; self.v = &self.v[..start]; Some(nth_back) + } else { + self.v = &self.v[..0]; // cheaper than &[] + None } } } @@ -2067,15 +2049,11 @@ impl<'a, T> Iterator for ChunksExactMut<'a, T> { #[inline] fn next(&mut self) -> Option<&'a mut [T]> { - if self.v.len() < self.chunk_size { - None - } else { - // SAFETY: self.chunk_size is inbounds because we compared above against self.v.len() - let (head, tail) = unsafe { self.v.split_at_mut(self.chunk_size) }; - self.v = tail; - // SAFETY: Nothing else points to or will point to the contents of this slice. - Some(unsafe { &mut *head }) - } + // SAFETY: we have `&mut self`, so are allowed to temporarily materialize a mut slice + unsafe { &mut *self.v }.split_at_mut_checked(self.chunk_size).and_then(|(chunk, rest)| { + self.v = rest; + Some(chunk) + }) } #[inline] @@ -2091,15 +2069,15 @@ impl<'a, T> Iterator for ChunksExactMut<'a, T> { #[inline] fn nth(&mut self, n: usize) -> Option<&'a mut [T]> { - let (start, overflow) = n.overflowing_mul(self.chunk_size); - if start >= self.v.len() || overflow { + if let Some(start) = n.checked_mul(self.chunk_size) + && start < self.v.len() + { + // SAFETY: `start < self.v.len()` + self.v = unsafe { self.v.split_at_mut(start).1 }; + self.next() + } else { self.v = &mut []; None - } else { - // SAFETY: The self.v contract ensures that any split_at_mut is valid. - let (_, snd) = unsafe { self.v.split_at_mut(start) }; - self.v = snd; - self.next() } } @@ -2133,10 +2111,7 @@ impl<'a, T> DoubleEndedIterator for ChunksExactMut<'a, T> { #[inline] fn nth_back(&mut self, n: usize) -> Option { let len = self.len(); - if n >= len { - self.v = &mut []; - None - } else { + if n < len { let start = (len - 1 - n) * self.chunk_size; let end = start + self.chunk_size; // SAFETY: The self.v contract ensures that any split_at_mut is valid. @@ -2146,6 +2121,9 @@ impl<'a, T> DoubleEndedIterator for ChunksExactMut<'a, T> { self.v = head; // SAFETY: Nothing else points to or will point to the contents of this slice. Some(unsafe { &mut *nth_back }) + } else { + self.v = &mut []; + None } } } @@ -2329,16 +2307,12 @@ impl<'a, T> Iterator for RChunks<'a, T> { if self.v.is_empty() { None } else { - let len = self.v.len(); - let chunksz = cmp::min(len, self.chunk_size); - // SAFETY: split_at_unchecked just requires the argument be less - // than the length. This could only happen if the expression `len - - // chunksz` overflows. This could only happen if `chunksz > len`, - // which is impossible as we initialize it as the `min` of `len` and - // `self.chunk_size`. - let (fst, snd) = unsafe { self.v.split_at_unchecked(len - chunksz) }; - self.v = fst; - Some(snd) + let idx = self.v.len().saturating_sub(self.chunk_size); + // SAFETY: self.chunk_size() > 0, so 0 <= idx < self.v.len(). + // Thus `idx` is in-bounds for `self.v` and can be used as a valid argument for `split_at_mut_unchecked`. + let (rest, chunk) = unsafe { self.v.split_at_unchecked(idx) }; + self.v = rest; + Some(chunk) } } @@ -2347,9 +2321,7 @@ impl<'a, T> Iterator for RChunks<'a, T> { if self.v.is_empty() { (0, Some(0)) } else { - let n = self.v.len() / self.chunk_size; - let rem = self.v.len() % self.chunk_size; - let n = if rem > 0 { n + 1 } else { n }; + let n = self.v.len().div_ceil(self.chunk_size); (n, Some(n)) } } @@ -2361,20 +2333,17 @@ impl<'a, T> Iterator for RChunks<'a, T> { #[inline] fn nth(&mut self, n: usize) -> Option { - let (end, overflow) = n.overflowing_mul(self.chunk_size); - if end >= self.v.len() || overflow { + if let Some(end) = n.checked_mul(self.chunk_size) + && end < self.v.len() + { + let end = self.v.len() - end; + let rest = &self.v[..end]; + let (rest, chunk) = rest.split_at(end.saturating_sub(self.chunk_size)); + self.v = rest; + Some(chunk) + } else { self.v = &self.v[..0]; // cheaper than &[] None - } else { - // Can't underflow because of the check above - let end = self.v.len() - end; - let start = match end.checked_sub(self.chunk_size) { - Some(sum) => sum, - None => 0, - }; - let nth = &self.v[start..end]; - self.v = &self.v[0..start]; - Some(nth) } } @@ -2391,10 +2360,7 @@ impl<'a, T> Iterator for RChunks<'a, T> { unsafe fn __iterator_get_unchecked(&mut self, idx: usize) -> Self::Item { let end = self.v.len() - idx * self.chunk_size; - let start = match end.checked_sub(self.chunk_size) { - None => 0, - Some(start) => start, - }; + let start = end.saturating_sub(self.chunk_size); // SAFETY: mostly identical to `Chunks::__iterator_get_unchecked`. unsafe { from_raw_parts(self.v.as_ptr().add(start), end - start) } } @@ -2419,17 +2385,16 @@ impl<'a, T> DoubleEndedIterator for RChunks<'a, T> { #[inline] fn nth_back(&mut self, n: usize) -> Option { let len = self.len(); - if n >= len { - self.v = &self.v[..0]; // cheaper than &[] - None - } else { - // can't underflow because `n < len` + if n < len { let offset_from_end = (len - 1 - n) * self.chunk_size; let end = self.v.len() - offset_from_end; let start = end.saturating_sub(self.chunk_size); let nth_back = &self.v[start..end]; self.v = &self.v[end..]; Some(nth_back) + } else { + self.v = &self.v[..0]; // cheaper than &[] + None } } } @@ -2501,17 +2466,13 @@ impl<'a, T> Iterator for RChunksMut<'a, T> { if self.v.is_empty() { None } else { - let sz = cmp::min(self.v.len(), self.chunk_size); - let len = self.v.len(); - // SAFETY: split_at_mut_unchecked just requires the argument be less - // than the length. This could only happen if the expression - // `len - sz` overflows. This could only happen if `sz > - // len`, which is impossible as we initialize it as the `min` of - // `self.v.len()` (e.g. `len`) and `self.chunk_size`. - let (head, tail) = unsafe { self.v.split_at_mut_unchecked(len - sz) }; - self.v = head; + let idx = self.v.len().saturating_sub(self.chunk_size); + // SAFETY: self.chunk_size() > 0, so 0 <= idx < self.v.len(). + // Thus `idx` is in-bounds for `self.v` and can be used as a valid argument for `split_at_mut_unchecked`. + let (rest, chunk) = unsafe { self.v.split_at_mut_unchecked(idx) }; + self.v = rest; // SAFETY: Nothing else points to or will point to the contents of this slice. - Some(unsafe { &mut *tail }) + Some(unsafe { &mut *chunk }) } } @@ -2520,9 +2481,7 @@ impl<'a, T> Iterator for RChunksMut<'a, T> { if self.v.is_empty() { (0, Some(0)) } else { - let n = self.v.len() / self.chunk_size; - let rem = self.v.len() % self.chunk_size; - let n = if rem > 0 { n + 1 } else { n }; + let n = self.v.len().div_ceil(self.chunk_size); (n, Some(n)) } } @@ -2534,12 +2493,9 @@ impl<'a, T> Iterator for RChunksMut<'a, T> { #[inline] fn nth(&mut self, n: usize) -> Option<&'a mut [T]> { - let (end, overflow) = n.overflowing_mul(self.chunk_size); - if end >= self.v.len() || overflow { - self.v = &mut []; - None - } else { - // Can't underflow because of the check above + if let Some(end) = n.checked_mul(self.chunk_size) + && end < self.v.len() + { let end = self.v.len() - end; let start = match end.checked_sub(self.chunk_size) { Some(sum) => sum, @@ -2554,6 +2510,9 @@ impl<'a, T> Iterator for RChunksMut<'a, T> { self.v = head; // SAFETY: Nothing else points to or will point to the contents of this slice. Some(unsafe { &mut *nth }) + } else { + self.v = &mut []; + None } } @@ -2571,10 +2530,7 @@ impl<'a, T> Iterator for RChunksMut<'a, T> { unsafe fn __iterator_get_unchecked(&mut self, idx: usize) -> Self::Item { let end = self.v.len() - idx * self.chunk_size; - let start = match end.checked_sub(self.chunk_size) { - None => 0, - Some(start) => start, - }; + let start = end.saturating_sub(self.chunk_size); // SAFETY: see comments for `RChunks::__iterator_get_unchecked` and // `ChunksMut::__iterator_get_unchecked`, `self.v`. unsafe { from_raw_parts_mut(self.v.as_mut_ptr().add(start), end - start) } @@ -2601,10 +2557,7 @@ impl<'a, T> DoubleEndedIterator for RChunksMut<'a, T> { #[inline] fn nth_back(&mut self, n: usize) -> Option { let len = self.len(); - if n >= len { - self.v = &mut []; - None - } else { + if n < len { // can't underflow because `n < len` let offset_from_end = (len - 1 - n) * self.chunk_size; let end = self.v.len() - offset_from_end; @@ -2616,6 +2569,9 @@ impl<'a, T> DoubleEndedIterator for RChunksMut<'a, T> { self.v = tail; // SAFETY: Nothing else points to or will point to the contents of this slice. Some(unsafe { &mut *nth_back }) + } else { + self.v = &mut []; + None } } } @@ -2746,14 +2702,14 @@ impl<'a, T> Iterator for RChunksExact<'a, T> { #[inline] fn nth(&mut self, n: usize) -> Option { - let (end, overflow) = n.overflowing_mul(self.chunk_size); - if end >= self.v.len() || overflow { + if let Some(end) = n.checked_mul(self.chunk_size) + && end < self.v.len() + { + self.v = &self.v[..self.v.len() - end]; + self.next() + } else { self.v = &self.v[..0]; // cheaper than &[] None - } else { - let (fst, _) = self.v.split_at(self.v.len() - end); - self.v = fst; - self.next() } } @@ -2786,10 +2742,7 @@ impl<'a, T> DoubleEndedIterator for RChunksExact<'a, T> { #[inline] fn nth_back(&mut self, n: usize) -> Option { let len = self.len(); - if n >= len { - self.v = &self.v[..0]; // cheaper than &[] - None - } else { + if n < len { // now that we know that `n` corresponds to a chunk, // none of these operations can underflow/overflow let offset = (len - n) * self.chunk_size; @@ -2798,6 +2751,9 @@ impl<'a, T> DoubleEndedIterator for RChunksExact<'a, T> { let nth_back = &self.v[start..end]; self.v = &self.v[end..]; Some(nth_back) + } else { + self.v = &self.v[..0]; // cheaper than &[] + None } } } @@ -2910,16 +2866,17 @@ impl<'a, T> Iterator for RChunksExactMut<'a, T> { #[inline] fn nth(&mut self, n: usize) -> Option<&'a mut [T]> { - let (end, overflow) = n.overflowing_mul(self.chunk_size); - if end >= self.v.len() || overflow { - self.v = &mut []; - None - } else { - let len = self.v.len(); + if let Some(end) = n.checked_mul(self.chunk_size) + && end < self.v.len() + { + let idx = self.v.len() - end; // SAFETY: The self.v contract ensures that any split_at_mut is valid. - let (fst, _) = unsafe { self.v.split_at_mut(len - end) }; + let (fst, _) = unsafe { self.v.split_at_mut(idx) }; self.v = fst; self.next() + } else { + self.v = &mut []; + None } } @@ -2954,10 +2911,7 @@ impl<'a, T> DoubleEndedIterator for RChunksExactMut<'a, T> { #[inline] fn nth_back(&mut self, n: usize) -> Option { let len = self.len(); - if n >= len { - self.v = &mut []; - None - } else { + if n < len { // now that we know that `n` corresponds to a chunk, // none of these operations can underflow/overflow let offset = (len - n) * self.chunk_size; @@ -2970,6 +2924,9 @@ impl<'a, T> DoubleEndedIterator for RChunksExactMut<'a, T> { self.v = tail; // SAFETY: Nothing else points to or will point to the contents of this slice. Some(unsafe { &mut *nth_back }) + } else { + self.v = &mut []; + None } } } diff --git a/coretests/tests/convert.rs b/coretests/tests/convert.rs index f1048f4cf09cb..1eb7468e56ea7 100644 --- a/coretests/tests/convert.rs +++ b/coretests/tests/convert.rs @@ -14,3 +14,20 @@ fn convert() { const BAR: Vec = into(Vec::new()); assert_eq!(BAR, Vec::::new()); } + +#[test] +fn into_as_try_into() { + struct A; + struct B; + + impl Into for A { + fn into(self) -> B { + B + } + } + + // This wouldn't compile if the `TryInto`/`TryFrom` blanket impls used + // `U: From` instead of `T: Into` + let Ok(B) = A.try_into(); + let Ok(B) = B::try_from(A); +} diff --git a/coretests/tests/io/borrowed_buf.rs b/coretests/tests/io/borrowed_buf.rs index aaa98d26ff8b9..730ba04465a11 100644 --- a/coretests/tests/io/borrowed_buf.rs +++ b/coretests/tests/io/borrowed_buf.rs @@ -8,7 +8,6 @@ fn new() { let mut rbuf: BorrowedBuf<'_> = buf.into(); assert_eq!(rbuf.filled().len(), 0); - assert_eq!(rbuf.init_len(), 16); assert_eq!(rbuf.capacity(), 16); assert_eq!(rbuf.unfilled().capacity(), 16); } @@ -20,27 +19,16 @@ fn uninit() { let mut rbuf: BorrowedBuf<'_> = buf.into(); assert_eq!(rbuf.filled().len(), 0); - assert_eq!(rbuf.init_len(), 0); assert_eq!(rbuf.capacity(), 16); assert_eq!(rbuf.unfilled().capacity(), 16); } -#[test] -fn initialize_unfilled() { - let buf: &mut [_] = &mut [MaybeUninit::uninit(); 16]; - let mut rbuf: BorrowedBuf<'_> = buf.into(); - - rbuf.unfilled().ensure_init(); - - assert_eq!(rbuf.init_len(), 16); -} - #[test] fn advance_filled() { let buf: &mut [_] = &mut [0; 16]; let mut rbuf: BorrowedBuf<'_> = buf.into(); - rbuf.unfilled().advance(1); + unsafe { rbuf.unfilled().advance(1) }; assert_eq!(rbuf.filled().len(), 1); assert_eq!(rbuf.unfilled().capacity(), 15); @@ -51,7 +39,7 @@ fn clear() { let buf: &mut [_] = &mut [255; 16]; let mut rbuf: BorrowedBuf<'_> = buf.into(); - rbuf.unfilled().advance(16); + unsafe { rbuf.unfilled().advance(16) }; assert_eq!(rbuf.filled().len(), 16); assert_eq!(rbuf.unfilled().capacity(), 0); @@ -61,33 +49,9 @@ fn clear() { assert_eq!(rbuf.filled().len(), 0); assert_eq!(rbuf.unfilled().capacity(), 16); - assert_eq!(rbuf.unfilled().init_mut(), [255; 16]); -} - -#[test] -fn set_init() { - let buf: &mut [_] = &mut [MaybeUninit::zeroed(); 16]; - let mut rbuf: BorrowedBuf<'_> = buf.into(); - - unsafe { - rbuf.set_init(8); - } - - assert_eq!(rbuf.init_len(), 8); - - rbuf.unfilled().advance(4); + unsafe { rbuf.unfilled().advance(16) }; - unsafe { - rbuf.set_init(2); - } - - assert_eq!(rbuf.init_len(), 8); - - unsafe { - rbuf.set_init(8); - } - - assert_eq!(rbuf.init_len(), 8); + assert_eq!(rbuf.filled(), [255; 16]); } #[test] @@ -97,7 +61,6 @@ fn append() { rbuf.unfilled().append(&[0; 8]); - assert_eq!(rbuf.init_len(), 8); assert_eq!(rbuf.filled().len(), 8); assert_eq!(rbuf.filled(), [0; 8]); @@ -105,7 +68,6 @@ fn append() { rbuf.unfilled().append(&[1; 16]); - assert_eq!(rbuf.init_len(), 16); assert_eq!(rbuf.filled().len(), 16); assert_eq!(rbuf.filled(), [1; 16]); } @@ -125,43 +87,12 @@ fn reborrow_written() { assert_eq!(cursor.written(), 32); assert_eq!(buf.unfilled().written(), 32); - assert_eq!(buf.init_len(), 32); assert_eq!(buf.filled().len(), 32); let filled = buf.filled(); assert_eq!(&filled[..16], [1; 16]); assert_eq!(&filled[16..], [2; 16]); } -#[test] -fn cursor_set_init() { - let buf: &mut [_] = &mut [MaybeUninit::zeroed(); 16]; - let mut rbuf: BorrowedBuf<'_> = buf.into(); - - unsafe { - rbuf.unfilled().set_init(8); - } - - assert_eq!(rbuf.init_len(), 8); - assert_eq!(rbuf.unfilled().init_mut().len(), 8); - assert_eq!(unsafe { rbuf.unfilled().as_mut().len() }, 16); - - rbuf.unfilled().advance(4); - - unsafe { - rbuf.unfilled().set_init(2); - } - - assert_eq!(rbuf.init_len(), 8); - - unsafe { - rbuf.unfilled().set_init(8); - } - - assert_eq!(rbuf.init_len(), 12); - assert_eq!(rbuf.unfilled().init_mut().len(), 8); - assert_eq!(unsafe { rbuf.unfilled().as_mut().len() }, 12); -} - #[test] fn cursor_with_unfilled_buf() { let buf: &mut [_] = &mut [MaybeUninit::uninit(); 16]; @@ -169,31 +100,30 @@ fn cursor_with_unfilled_buf() { let mut cursor = rbuf.unfilled(); cursor.with_unfilled_buf(|buf| { + assert_eq!(buf.capacity(), 16); buf.unfilled().append(&[1, 2, 3]); assert_eq!(buf.filled(), &[1, 2, 3]); }); - assert_eq!(cursor.init_mut().len(), 0); assert_eq!(cursor.written(), 3); cursor.with_unfilled_buf(|buf| { assert_eq!(buf.capacity(), 13); - assert_eq!(buf.init_len(), 0); - buf.unfilled().ensure_init(); - buf.unfilled().advance(4); + unsafe { + buf.unfilled().as_mut().write_filled(0); + buf.unfilled().advance(4) + }; }); - assert_eq!(cursor.init_mut().len(), 9); assert_eq!(cursor.written(), 7); cursor.with_unfilled_buf(|buf| { assert_eq!(buf.capacity(), 9); - assert_eq!(buf.init_len(), 9); }); - assert_eq!(cursor.init_mut().len(), 9); assert_eq!(cursor.written(), 7); + assert_eq!(rbuf.len(), 7); assert_eq!(rbuf.filled(), &[1, 2, 3, 0, 0, 0, 0]); } diff --git a/coretests/tests/slice.rs b/coretests/tests/slice.rs index 110c4e5f3b406..6f60f71e8a477 100644 --- a/coretests/tests/slice.rs +++ b/coretests/tests/slice.rs @@ -432,6 +432,13 @@ fn test_chunks_exact_mut_zip_aliasing() { assert_eq!(first, (&mut [0, 1][..], &[6, 7][..])); } +#[test] +fn test_chunks_zst() { + const SIZE: usize = 16; + let mut it = [(); usize::MAX].chunks(SIZE); + assert_eq!(it.nth_back(0), Some(&[(); SIZE - 1][..])); +} + #[test] fn test_rchunks_mut_zip_aliasing() { let v1: &mut [i32] = &mut [0, 1, 2, 3, 4]; diff --git a/std/src/fs/tests.rs b/std/src/fs/tests.rs index 0a5d1153d860c..bcaafcfee787a 100644 --- a/std/src/fs/tests.rs +++ b/std/src/fs/tests.rs @@ -709,8 +709,6 @@ fn file_test_read_buf() { let mut file = check!(File::open(filename)); check!(file.read_buf(buf.unfilled())); assert_eq!(buf.filled(), &[1, 2, 3, 4]); - // File::read_buf should omit buffer initialization. - assert_eq!(buf.init_len(), 4); check!(fs::remove_file(filename)); } diff --git a/std/src/io/buffered/bufreader.rs b/std/src/io/buffered/bufreader.rs index 40441dc057d0d..69c260b5410af 100644 --- a/std/src/io/buffered/bufreader.rs +++ b/std/src/io/buffered/bufreader.rs @@ -284,15 +284,6 @@ impl BufReader { } } -// This is only used by a test which asserts that the initialization-tracking is correct. -#[cfg(test)] -impl BufReader { - #[allow(missing_docs)] - pub fn initialized(&self) -> usize { - self.buf.initialized() - } -} - impl BufReader { /// Seeks relative to the current position. If the new position lies within the buffer, /// the buffer will not be flushed, allowing for more efficient seeks. diff --git a/std/src/io/buffered/bufreader/buffer.rs b/std/src/io/buffered/bufreader/buffer.rs index 9b600cd55758b..2694726b3f44f 100644 --- a/std/src/io/buffered/bufreader/buffer.rs +++ b/std/src/io/buffered/bufreader/buffer.rs @@ -21,25 +21,19 @@ pub struct Buffer { // Each call to `fill_buf` sets `filled` to indicate how many bytes at the start of `buf` are // initialized with bytes from a read. filled: usize, - // This is the max number of bytes returned across all `fill_buf` calls. We track this so that we - // can accurately tell `read_buf` how many bytes of buf are initialized, to bypass as much of its - // defensive initialization as possible. Note that while this often the same as `filled`, it - // doesn't need to be. Calls to `fill_buf` are not required to actually fill the buffer, and - // omitting this is a huge perf regression for `Read` impls that do not. - initialized: usize, } impl Buffer { #[inline] pub fn with_capacity(capacity: usize) -> Self { let buf = Box::new_uninit_slice(capacity); - Self { buf, pos: 0, filled: 0, initialized: 0 } + Self { buf, pos: 0, filled: 0 } } #[inline] pub fn try_with_capacity(capacity: usize) -> io::Result { match Box::try_new_uninit_slice(capacity) { - Ok(buf) => Ok(Self { buf, pos: 0, filled: 0, initialized: 0 }), + Ok(buf) => Ok(Self { buf, pos: 0, filled: 0 }), Err(_) => { Err(io::const_error!(ErrorKind::OutOfMemory, "failed to allocate read buffer")) } @@ -68,12 +62,6 @@ impl Buffer { self.pos } - // This is only used by a test which asserts that the initialization-tracking is correct. - #[cfg(test)] - pub fn initialized(&self) -> usize { - self.initialized - } - #[inline] pub fn discard_buffer(&mut self) { self.pos = 0; @@ -110,13 +98,8 @@ impl Buffer { /// 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.filled..]); - let old_init = self.initialized - self.filled; - unsafe { - buf.set_init(old_init); - } reader.read_buf(buf.unfilled())?; self.filled += buf.len(); - self.initialized += buf.init_len() - old_init; Ok(buf.len()) } @@ -137,16 +120,10 @@ impl Buffer { debug_assert!(self.pos == self.filled); let mut buf = BorrowedBuf::from(&mut *self.buf); - // SAFETY: `self.filled` bytes will always have been initialized. - unsafe { - buf.set_init(self.initialized); - } - let result = reader.read_buf(buf.unfilled()); self.pos = 0; self.filled = buf.len(); - self.initialized = buf.init_len(); result?; } diff --git a/std/src/io/buffered/tests.rs b/std/src/io/buffered/tests.rs index 17f6107aa030c..068dca819775a 100644 --- a/std/src/io/buffered/tests.rs +++ b/std/src/io/buffered/tests.rs @@ -1052,30 +1052,6 @@ fn single_formatted_write() { assert_eq!(writer.get_ref().events, [RecordedEvent::Write("hello, world!\n".to_string())]); } -#[test] -fn bufreader_full_initialize() { - struct OneByteReader; - impl Read for OneByteReader { - fn read(&mut self, buf: &mut [u8]) -> crate::io::Result { - if buf.len() > 0 { - buf[0] = 0; - Ok(1) - } else { - Ok(0) - } - } - } - let mut reader = BufReader::new(OneByteReader); - // Nothing is initialized yet. - assert_eq!(reader.initialized(), 0); - - let buf = reader.fill_buf().unwrap(); - // We read one byte... - assert_eq!(buf.len(), 1); - // But we initialized the whole buffer! - assert_eq!(reader.initialized(), reader.capacity()); -} - /// This is a regression test for https://github.com/rust-lang/rust/issues/127584. #[test] fn bufwriter_aliasing() { diff --git a/std/src/io/copy.rs b/std/src/io/copy.rs index 2b558efb8885e..8b5e7c4df4e08 100644 --- a/std/src/io/copy.rs +++ b/std/src/io/copy.rs @@ -214,28 +214,19 @@ impl BufferedWriterSpec for BufWriter { } let mut len = 0; - let mut init = 0; loop { let buf = self.buffer_mut(); let mut read_buf: BorrowedBuf<'_> = buf.spare_capacity_mut().into(); - unsafe { - // 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 { let mut cursor = read_buf.unfilled(); match reader.read_buf(cursor.reborrow()) { Ok(()) => { let bytes_read = cursor.written(); - if bytes_read == 0 { return Ok(len); } - - init = read_buf.init_len() - bytes_read; len += bytes_read as u64; // SAFETY: BorrowedBuf guarantees all of its filled bytes are init @@ -248,10 +239,6 @@ impl BufferedWriterSpec for BufWriter { Err(e) => return Err(e), } } else { - // All the bytes that were already in the buffer are initialized, - // treat them as such when the buffer is flushed. - init += buf.len(); - self.flush_buf()?; } } diff --git a/std/src/io/mod.rs b/std/src/io/mod.rs index b7756befa11e9..4c064c435e5bc 100644 --- a/std/src/io/mod.rs +++ b/std/src/io/mod.rs @@ -419,8 +419,6 @@ pub(crate) fn default_read_to_end( .and_then(|s| s.checked_add(1024)?.checked_next_multiple_of(DEFAULT_BUF_SIZE)) .unwrap_or(DEFAULT_BUF_SIZE); - let mut initialized = 0; // Extra initialized bytes from previous loop iteration - const PROBE_SIZE: usize = 32; fn small_probe_read(r: &mut R, buf: &mut Vec) -> Result { @@ -449,8 +447,6 @@ pub(crate) fn default_read_to_end( } } - let mut consecutive_short_reads = 0; - loop { if buf.len() == buf.capacity() && buf.capacity() == start_cap { // The buffer might be an exact fit. Let's read into a probe buffer @@ -474,11 +470,6 @@ pub(crate) fn default_read_to_end( spare = &mut spare[..buf_len]; let mut read_buf: BorrowedBuf<'_> = spare.into(); - // SAFETY: These bytes were initialized but not filled in the previous loop - unsafe { - read_buf.set_init(initialized); - } - let mut cursor = read_buf.unfilled(); let result = loop { match r.read_buf(cursor.reborrow()) { @@ -489,9 +480,7 @@ pub(crate) fn default_read_to_end( } }; - let unfilled_but_initialized = cursor.init_mut().len(); let bytes_read = cursor.written(); - let was_fully_initialized = read_buf.init_len() == buf_len; // SAFETY: BorrowedBuf's invariants mean this much memory is initialized. unsafe { @@ -506,27 +495,8 @@ pub(crate) fn default_read_to_end( return Ok(buf.len() - start_len); } - if bytes_read < buf_len { - consecutive_short_reads += 1; - } else { - consecutive_short_reads = 0; - } - - // store how much was initialized but not filled - initialized = unfilled_but_initialized; - // Use heuristics to determine the max read size if no initial size hint was provided if size_hint.is_none() { - // The reader is returning short reads but it doesn't call ensure_init(). - // In that case we no longer need to restrict read sizes to avoid - // initialization costs. - // When reading from disk we usually don't get any short reads except at EOF. - // So we wait for at least 2 short reads before uncapping the read buffer; - // this helps with the Windows issue. - if !was_fully_initialized && consecutive_short_reads > 1 { - max_read_size = usize::MAX; - } - // we have passed a larger buffer than previously and the // reader still hasn't returned a short read if buf_len >= max_read_size && bytes_read == buf_len { @@ -587,8 +557,13 @@ pub(crate) fn default_read_buf(read: F, mut cursor: BorrowedCursor<'_>) -> Re where F: FnOnce(&mut [u8]) -> Result, { - let n = read(cursor.ensure_init().init_mut())?; - cursor.advance(n); + // SAFETY: We do not uninitialize any part of the buffer. + let n = read(unsafe { cursor.as_mut().write_filled(0) })?; + assert!(n <= cursor.capacity()); + // SAFETY: We've initialized the entire buffer, and `read` can't make it uninitialized. + unsafe { + cursor.advance(n); + } Ok(()) } @@ -3098,31 +3073,21 @@ impl Read for Take { // The condition above guarantees that `self.limit` fits in `usize`. let limit = self.limit as usize; - let extra_init = cmp::min(limit, buf.init_mut().len()); - // SAFETY: no uninit data is written to ibuf let ibuf = unsafe { &mut buf.as_mut()[..limit] }; let mut sliced_buf: BorrowedBuf<'_> = ibuf.into(); - // SAFETY: extra_init bytes of ibuf are known to be initialized - unsafe { - sliced_buf.set_init(extra_init); - } - let mut cursor = sliced_buf.unfilled(); let result = self.inner.read_buf(cursor.reborrow()); - let new_init = cursor.init_mut().len(); let filled = sliced_buf.len(); // cursor / sliced_buf / ibuf must drop here + // SAFETY: filled bytes have been filled and therefore initialized unsafe { - // SAFETY: filled bytes have been filled and therefore initialized - buf.advance_unchecked(filled); - // SAFETY: new_init bytes of buf's unfilled buffer have been initialized - buf.set_init(new_init); + buf.advance(filled); } self.limit -= filled as u64; diff --git a/std/src/io/tests.rs b/std/src/io/tests.rs index b22988d4a8a9d..e14e6432eafaf 100644 --- a/std/src/io/tests.rs +++ b/std/src/io/tests.rs @@ -209,15 +209,6 @@ fn read_buf_exact() { assert_eq!(c.read_buf_exact(buf.unfilled()).unwrap_err().kind(), io::ErrorKind::UnexpectedEof); } -#[test] -#[should_panic] -fn borrowed_cursor_advance_overflow() { - let mut buf = [0; 512]; - let mut buf = BorrowedBuf::from(&mut buf[..]); - buf.unfilled().advance(1); - buf.unfilled().advance(usize::MAX); -} - #[test] fn take_eof() { struct R; diff --git a/std/src/io/util.rs b/std/src/io/util.rs index 0410df3ef1a3e..a09c8bc069306 100644 --- a/std/src/io/util.rs +++ b/std/src/io/util.rs @@ -283,7 +283,7 @@ impl Read for Repeat { // SAFETY: No uninit bytes are being written. unsafe { buf.as_mut() }.write_filled(self.byte); // SAFETY: the entire unfilled portion of buf has been initialized. - unsafe { buf.advance_unchecked(buf.capacity()) }; + unsafe { buf.advance(buf.capacity()) }; Ok(()) } diff --git a/std/src/io/util/tests.rs b/std/src/io/util/tests.rs index d0f106d7af416..92dbc3919bea2 100644 --- a/std/src/io/util/tests.rs +++ b/std/src/io/util/tests.rs @@ -75,43 +75,36 @@ fn empty_reads() { let mut buf: BorrowedBuf<'_> = buf.into(); e.read_buf(buf.unfilled()).unwrap(); assert_eq!(buf.len(), 0); - assert_eq!(buf.init_len(), 0); let buf: &mut [_] = &mut [MaybeUninit::uninit()]; let mut buf: BorrowedBuf<'_> = buf.into(); e.read_buf(buf.unfilled()).unwrap(); assert_eq!(buf.len(), 0); - assert_eq!(buf.init_len(), 0); let buf: &mut [_] = &mut [MaybeUninit::uninit(); 1024]; let mut buf: BorrowedBuf<'_> = buf.into(); e.read_buf(buf.unfilled()).unwrap(); assert_eq!(buf.len(), 0); - assert_eq!(buf.init_len(), 0); let buf: &mut [_] = &mut [MaybeUninit::uninit(); 1024]; let mut buf: BorrowedBuf<'_> = buf.into(); Read::by_ref(&mut e).read_buf(buf.unfilled()).unwrap(); assert_eq!(buf.len(), 0); - assert_eq!(buf.init_len(), 0); let buf: &mut [MaybeUninit<_>] = &mut []; let mut buf: BorrowedBuf<'_> = buf.into(); e.read_buf_exact(buf.unfilled()).unwrap(); assert_eq!(buf.len(), 0); - assert_eq!(buf.init_len(), 0); let buf: &mut [_] = &mut [MaybeUninit::uninit()]; let mut buf: BorrowedBuf<'_> = buf.into(); assert_eq!(e.read_buf_exact(buf.unfilled()).unwrap_err().kind(), ErrorKind::UnexpectedEof); assert_eq!(buf.len(), 0); - assert_eq!(buf.init_len(), 0); let buf: &mut [_] = &mut [MaybeUninit::uninit(); 1024]; let mut buf: BorrowedBuf<'_> = buf.into(); assert_eq!(e.read_buf_exact(buf.unfilled()).unwrap_err().kind(), ErrorKind::UnexpectedEof); assert_eq!(buf.len(), 0); - assert_eq!(buf.init_len(), 0); let buf: &mut [_] = &mut [MaybeUninit::uninit(); 1024]; let mut buf: BorrowedBuf<'_> = buf.into(); @@ -120,7 +113,6 @@ fn empty_reads() { ErrorKind::UnexpectedEof, ); assert_eq!(buf.len(), 0); - assert_eq!(buf.init_len(), 0); let mut buf = Vec::new(); assert_eq!(e.read_to_end(&mut buf).unwrap(), 0); diff --git a/std/src/net/tcp/tests.rs b/std/src/net/tcp/tests.rs index 7c7ef7b2f7018..4787f8a1040b9 100644 --- a/std/src/net/tcp/tests.rs +++ b/std/src/net/tcp/tests.rs @@ -315,8 +315,6 @@ fn read_buf() { let mut buf = BorrowedBuf::from(buf.as_mut_slice()); t!(s.read_buf(buf.unfilled())); assert_eq!(buf.filled(), &[1, 2, 3, 4]); - // TcpStream::read_buf should omit buffer initialization. - assert_eq!(buf.init_len(), 4); t.join().ok().expect("thread panicked"); }) diff --git a/std/src/process/tests.rs b/std/src/process/tests.rs index 12c5130defe5a..c8a83edffe427 100644 --- a/std/src/process/tests.rs +++ b/std/src/process/tests.rs @@ -188,10 +188,8 @@ fn child_stdout_read_buf() { // ChildStdout::read_buf should omit buffer initialization. if cfg!(target_os = "windows") { assert_eq!(buf.filled(), b"abc\r\n"); - assert_eq!(buf.init_len(), 5); } else { assert_eq!(buf.filled(), b"abc\n"); - assert_eq!(buf.init_len(), 4); }; } diff --git a/std/src/sys/fd/hermit.rs b/std/src/sys/fd/hermit.rs index 7e8ba065f1b96..afcd8c6355416 100644 --- a/std/src/sys/fd/hermit.rs +++ b/std/src/sys/fd/hermit.rs @@ -34,7 +34,7 @@ impl FileDesc { ) })?; // SAFETY: Exactly `result` bytes have been filled. - unsafe { buf.advance_unchecked(result as usize) }; + unsafe { buf.advance(result as usize) }; Ok(()) } diff --git a/std/src/sys/fd/unix.rs b/std/src/sys/fd/unix.rs index 2b2dfe48e89e2..a631e1d91393f 100644 --- a/std/src/sys/fd/unix.rs +++ b/std/src/sys/fd/unix.rs @@ -185,7 +185,7 @@ impl FileDesc { // SAFETY: `ret` bytes were written to the initialized portion of the buffer unsafe { - cursor.advance_unchecked(ret as usize); + cursor.advance(ret as usize); } Ok(()) } @@ -203,7 +203,7 @@ impl FileDesc { // SAFETY: `ret` bytes were written to the initialized portion of the buffer unsafe { - cursor.advance_unchecked(ret as usize); + cursor.advance(ret as usize); } Ok(()) } diff --git a/std/src/sys/fd/wasi.rs b/std/src/sys/fd/wasi.rs index 80a5143ff0b00..a468b31168afa 100644 --- a/std/src/sys/fd/wasi.rs +++ b/std/src/sys/fd/wasi.rs @@ -59,7 +59,7 @@ impl WasiFd { }]; match wasi::fd_read(self.as_raw_fd() as wasi::Fd, &bufs) { Ok(n) => { - buf.advance_unchecked(n); + buf.advance(n); Ok(()) } Err(e) => Err(err2io(e)), diff --git a/std/src/sys/fs/solid.rs b/std/src/sys/fs/solid.rs index f6d5d3b784d3b..ec1db262855ad 100644 --- a/std/src/sys/fs/solid.rs +++ b/std/src/sys/fs/solid.rs @@ -401,7 +401,7 @@ impl File { // Safety: `num_bytes_read` bytes were written to the unfilled // portion of the buffer - cursor.advance_unchecked(num_bytes_read); + cursor.advance(num_bytes_read); Ok(()) } diff --git a/std/src/sys/fs/uefi.rs b/std/src/sys/fs/uefi.rs index bd4ae56974f0c..44f8b6e80f903 100644 --- a/std/src/sys/fs/uefi.rs +++ b/std/src/sys/fs/uefi.rs @@ -18,9 +18,8 @@ pub struct File(!); pub struct FileAttr { attr: u64, size: u64, - accessed: SystemTime, - modified: SystemTime, - created: SystemTime, + file_time: FileTimes, + created: Option, } pub struct ReadDir(!); @@ -66,15 +65,20 @@ impl FileAttr { } pub fn modified(&self) -> io::Result { - Ok(self.modified) + self.file_time + .modified + .ok_or(io::const_error!(io::ErrorKind::InvalidData, "modification time is not valid")) } pub fn accessed(&self) -> io::Result { - Ok(self.accessed) + self.file_time + .accessed + .ok_or(io::const_error!(io::ErrorKind::InvalidData, "last access time is not valid")) } pub fn created(&self) -> io::Result { - Ok(self.created) + self.created + .ok_or(io::const_error!(io::ErrorKind::InvalidData, "creation time is not valid")) } fn from_uefi(info: helpers::UefiBox) -> Self { @@ -82,8 +86,10 @@ impl FileAttr { Self { attr: (*info.as_ptr()).attribute, size: (*info.as_ptr()).file_size, - modified: uefi_fs::uefi_to_systemtime((*info.as_ptr()).modification_time), - accessed: uefi_fs::uefi_to_systemtime((*info.as_ptr()).last_access_time), + file_time: FileTimes { + modified: uefi_fs::uefi_to_systemtime((*info.as_ptr()).modification_time), + accessed: uefi_fs::uefi_to_systemtime((*info.as_ptr()).last_access_time), + }, created: uefi_fs::uefi_to_systemtime((*info.as_ptr()).create_time), } } @@ -627,9 +633,9 @@ mod uefi_fs { /// EDK2 FAT driver uses EFI_UNSPECIFIED_TIMEZONE to represent localtime. So for proper /// conversion to SystemTime, we use the current time to get the timezone in such cases. - pub(crate) fn uefi_to_systemtime(mut time: r_efi::efi::Time) -> SystemTime { + pub(crate) fn uefi_to_systemtime(mut time: r_efi::efi::Time) -> Option { time.timezone = if time.timezone == r_efi::efi::UNSPECIFIED_TIMEZONE { - time::system_time_internal::now().unwrap().timezone + time::system_time_internal::now().timezone } else { time.timezone }; @@ -639,7 +645,7 @@ mod uefi_fs { /// Convert to UEFI Time with the current timezone. #[expect(dead_code)] fn systemtime_to_uefi(time: SystemTime) -> r_efi::efi::Time { - let now = time::system_time_internal::now().unwrap(); + let now = time::system_time_internal::now(); time.to_uefi_loose(now.timezone, now.daylight) } } diff --git a/std/src/sys/net/connection/socket/hermit.rs b/std/src/sys/net/connection/socket/hermit.rs index 2f5c6fa31d407..f044bf8dfae08 100644 --- a/std/src/sys/net/connection/socket/hermit.rs +++ b/std/src/sys/net/connection/socket/hermit.rs @@ -143,7 +143,7 @@ impl Socket { ) })?; unsafe { - buf.advance_unchecked(ret as usize); + buf.advance(ret as usize); } Ok(()) } diff --git a/std/src/sys/net/connection/socket/solid.rs b/std/src/sys/net/connection/socket/solid.rs index 14cf75adcc06f..731157ec319c5 100644 --- a/std/src/sys/net/connection/socket/solid.rs +++ b/std/src/sys/net/connection/socket/solid.rs @@ -191,7 +191,7 @@ impl Socket { netc::recv(self.as_raw_fd(), buf.as_mut().as_mut_ptr().cast(), buf.capacity(), flags) })?; unsafe { - buf.advance_unchecked(ret as usize); + buf.advance(ret as usize); } Ok(()) } diff --git a/std/src/sys/net/connection/socket/unix.rs b/std/src/sys/net/connection/socket/unix.rs index 559e27604a9d3..c892daf0d39c3 100644 --- a/std/src/sys/net/connection/socket/unix.rs +++ b/std/src/sys/net/connection/socket/unix.rs @@ -293,7 +293,7 @@ impl Socket { ) })?; unsafe { - buf.advance_unchecked(ret as usize); + buf.advance(ret as usize); } Ok(()) } diff --git a/std/src/sys/net/connection/socket/wasip2.rs b/std/src/sys/net/connection/socket/wasip2.rs index a1b08609eb024..f86034266c26a 100644 --- a/std/src/sys/net/connection/socket/wasip2.rs +++ b/std/src/sys/net/connection/socket/wasip2.rs @@ -167,7 +167,7 @@ impl Socket { ) })?; unsafe { - buf.advance_unchecked(ret as usize); + buf.advance(ret as usize); } Ok(()) } diff --git a/std/src/sys/net/connection/socket/windows.rs b/std/src/sys/net/connection/socket/windows.rs index 6dbebc5e276ec..08196d61aa30d 100644 --- a/std/src/sys/net/connection/socket/windows.rs +++ b/std/src/sys/net/connection/socket/windows.rs @@ -244,7 +244,7 @@ impl Socket { } } _ => { - unsafe { buf.advance_unchecked(result as usize) }; + unsafe { buf.advance(result as usize) }; Ok(()) } } diff --git a/std/src/sys/pal/sgx/abi/usercalls/mod.rs b/std/src/sys/pal/sgx/abi/usercalls/mod.rs index 5041770faf661..f1e4a5a42577a 100644 --- a/std/src/sys/pal/sgx/abi/usercalls/mod.rs +++ b/std/src/sys/pal/sgx/abi/usercalls/mod.rs @@ -46,7 +46,7 @@ pub fn read_buf(fd: Fd, mut buf: BorrowedCursor<'_>) -> IoResult<()> { let mut userbuf = alloc::User::<[u8]>::uninitialized(buf.capacity()); let len = raw::read(fd, userbuf.as_mut_ptr().cast(), userbuf.len()).from_sgx_result()?; userbuf[..len].copy_to_enclave(&mut buf.as_mut()[..len]); - buf.advance_unchecked(len); + buf.advance(len); Ok(()) } } diff --git a/std/src/sys/pal/uefi/time.rs b/std/src/sys/pal/uefi/time.rs index f9f90a454976a..28dacbe3068a7 100644 --- a/std/src/sys/pal/uefi/time.rs +++ b/std/src/sys/pal/uefi/time.rs @@ -24,7 +24,8 @@ pub const UNIX_EPOCH: SystemTime = SystemTime::from_uefi(r_efi::efi::Time { daylight: 0, pad1: 0, pad2: 0, -}); +}) +.unwrap(); const MAX_UEFI_TIME: SystemTime = SystemTime::from_uefi(r_efi::efi::Time { year: 9999, @@ -38,7 +39,8 @@ const MAX_UEFI_TIME: SystemTime = SystemTime::from_uefi(r_efi::efi::Time { daylight: 0, pad1: 0, pad2: 0, -}); +}) +.unwrap(); impl Instant { pub fn now() -> Instant { @@ -68,8 +70,11 @@ impl Instant { } impl SystemTime { - pub(crate) const fn from_uefi(t: r_efi::efi::Time) -> Self { - Self(system_time_internal::from_uefi(&t)) + pub(crate) const fn from_uefi(t: r_efi::efi::Time) -> Option { + match system_time_internal::from_uefi(&t) { + Some(x) => Some(Self(x)), + None => None, + } } pub(crate) const fn to_uefi( @@ -96,9 +101,8 @@ impl SystemTime { } pub fn now() -> SystemTime { - system_time_internal::now() - .map(Self::from_uefi) - .unwrap_or_else(|| panic!("time not implemented on this platform")) + Self::from_uefi(system_time_internal::now()) + .expect("time incorrectly implemented on this platform") } pub fn sub_time(&self, other: &SystemTime) -> Result { @@ -129,17 +133,18 @@ pub(crate) mod system_time_internal { const SECS_IN_DAY: u64 = SECS_IN_HOUR * 24; const SYSTEMTIME_TIMEZONE: i64 = -1440 * SECS_IN_MINUTE as i64; - pub(crate) fn now() -> Option