Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
35 changes: 35 additions & 0 deletions library/alloc/src/vec/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down Expand Up @@ -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> {
Expand Down
55 changes: 55 additions & 0 deletions library/alloc/src/vec/peek_mut.rs
Original file line number Diff line number Diff line change
@@ -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) }
}
}
1 change: 1 addition & 0 deletions library/alloctests/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand Down
11 changes: 11 additions & 0 deletions library/alloctests/tests/vec.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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!
Expand Down
Loading