add Vec::peek_mut

This commit is contained in:
Jeremy Smart 2025-06-04 18:15:12 -04:00
parent 59aa1e8730
commit 188c40126d
No known key found for this signature in database
GPG key ID: 5AD8086D5DF29A8F
4 changed files with 102 additions and 0 deletions

View file

@ -109,6 +109,11 @@ mod in_place_collect;
mod partial_eq;
#[unstable(feature = "vec_peek_mut", issue = "122742")]
pub use self::peek_mut::PeekMut;
mod peek_mut;
#[cfg(not(no_global_oom_handling))]
use self::spec_from_elem::SpecFromElem;
@ -729,6 +734,36 @@ impl<T> Vec<T> {
pub unsafe fn from_parts(ptr: NonNull<T>, length: usize, capacity: usize) -> Self {
unsafe { Self::from_parts_in(ptr, length, capacity, Global) }
}
/// Returns a mutable reference to the greatest item in the binary heap, or
/// `None` if it is empty.
///
/// Note: If the `PeekMut` value is leaked, some heap elements might get
/// leaked along with it, but the remaining elements will remain a valid
/// heap.
///
/// # Examples
///
/// Basic usage:
///
/// ```
/// let mut vec = Vec::new();
/// assert!(vec.peek_mut().is_none());
///
/// vec.push(1);
/// vec.push(5);
/// vec.push(2);
/// assert_eq!(vec.last(), Some(&2));
/// if let Some(mut val) = vec.peek_mut() {
/// *val = 0;
/// }
/// assert_eq!(vec.last(), Some(&0));
/// ```
#[inline]
#[unstable(feature = "vec_peek_mut", issue = "122742")]
pub fn peek_mut(&mut self) -> Option<PeekMut<'_, T>> {
PeekMut::new(self)
}
}
impl<T, A: Allocator> Vec<T, A> {

View file

@ -0,0 +1,55 @@
use core::ops::{Deref, DerefMut};
use super::Vec;
use crate::fmt;
/// Structure wrapping a mutable reference to the last item in a
/// `Vec`.
///
/// This `struct` is created by the [`peek_mut`] method on [`Vec`]. See
/// its documentation for more.
///
/// [`peek_mut`]: Vec::peek_mut
#[unstable(feature = "vec_peek_mut", issue = "122742")]
pub struct PeekMut<'a, T> {
vec: &'a mut Vec<T>,
}
#[unstable(feature = "vec_peek_mut", issue = "122742")]
impl<T: fmt::Debug> fmt::Debug for PeekMut<'_, T> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_tuple("PeekMut").field(self.deref()).finish()
}
}
impl<'a, T> PeekMut<'a, T> {
pub(crate) fn new(vec: &'a mut Vec<T>) -> Option<Self> {
if vec.is_empty() { None } else { Some(Self { vec }) }
}
/// Removes the peeked value from the vector and returns it.
#[unstable(feature = "vec_peek_mut", issue = "122742")]
pub fn pop(self) -> T {
// SAFETY: PeekMut is only constructed if the vec is non-empty
unsafe { self.vec.pop().unwrap_unchecked() }
}
}
#[unstable(feature = "vec_peek_mut", issue = "122742")]
impl<'a, T> Deref for PeekMut<'a, T> {
type Target = T;
fn deref(&self) -> &Self::Target {
// SAFETY: PeekMut is only constructed if the vec is non-empty
unsafe { self.vec.get_unchecked(self.vec.len() - 1) }
}
}
#[unstable(feature = "vec_peek_mut", issue = "122742")]
impl<'a, T> DerefMut for PeekMut<'a, T> {
fn deref_mut(&mut self) -> &mut Self::Target {
let idx = self.vec.len() - 1;
// SAFETY: PeekMut is only constructed if the vec is non-empty
unsafe { self.vec.get_unchecked_mut(idx) }
}
}

View file

@ -42,6 +42,7 @@
#![feature(trusted_random_access)]
#![feature(try_reserve_kind)]
#![feature(try_trait_v2)]
#![feature(vec_peek_mut)]
// tidy-alphabetical-end
//
// Language features:

View file

@ -2698,6 +2698,17 @@ fn test_pop_if_mutates() {
assert_eq!(v, [2]);
}
#[test]
fn test_peek_mut() {
let mut vec = Vec::new();
assert!(vec.peek_mut().is_none());
vec.push(1);
vec.push(2);
assert_eq!(vec.peek_mut(), Some(2));
*vec.peek_mut() = 0;
assert_eq!(vec.peek_mut(), Some(0));
}
/// This assortment of tests, in combination with miri, verifies we handle UB on fishy arguments
/// in the stdlib. Draining and extending the allocation are fairly well-tested earlier, but
/// `vec.insert(usize::MAX, val)` once slipped by!