Skip to content

Commit 188c401

Browse files
committed
add Vec::peek_mut
1 parent 59aa1e8 commit 188c401

File tree

4 files changed

+102
-0
lines changed

4 files changed

+102
-0
lines changed

library/alloc/src/vec/mod.rs

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -109,6 +109,11 @@ mod in_place_collect;
109109

110110
mod partial_eq;
111111

112+
#[unstable(feature = "vec_peek_mut", issue = "122742")]
113+
pub use self::peek_mut::PeekMut;
114+
115+
mod peek_mut;
116+
112117
#[cfg(not(no_global_oom_handling))]
113118
use self::spec_from_elem::SpecFromElem;
114119

@@ -729,6 +734,36 @@ impl<T> Vec<T> {
729734
pub unsafe fn from_parts(ptr: NonNull<T>, length: usize, capacity: usize) -> Self {
730735
unsafe { Self::from_parts_in(ptr, length, capacity, Global) }
731736
}
737+
738+
/// Returns a mutable reference to the greatest item in the binary heap, or
739+
/// `None` if it is empty.
740+
///
741+
/// Note: If the `PeekMut` value is leaked, some heap elements might get
742+
/// leaked along with it, but the remaining elements will remain a valid
743+
/// heap.
744+
///
745+
/// # Examples
746+
///
747+
/// Basic usage:
748+
///
749+
/// ```
750+
/// let mut vec = Vec::new();
751+
/// assert!(vec.peek_mut().is_none());
752+
///
753+
/// vec.push(1);
754+
/// vec.push(5);
755+
/// vec.push(2);
756+
/// assert_eq!(vec.last(), Some(&2));
757+
/// if let Some(mut val) = vec.peek_mut() {
758+
/// *val = 0;
759+
/// }
760+
/// assert_eq!(vec.last(), Some(&0));
761+
/// ```
762+
#[inline]
763+
#[unstable(feature = "vec_peek_mut", issue = "122742")]
764+
pub fn peek_mut(&mut self) -> Option<PeekMut<'_, T>> {
765+
PeekMut::new(self)
766+
}
732767
}
733768

734769
impl<T, A: Allocator> Vec<T, A> {

library/alloc/src/vec/peek_mut.rs

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
use core::ops::{Deref, DerefMut};
2+
3+
use super::Vec;
4+
use crate::fmt;
5+
6+
/// Structure wrapping a mutable reference to the last item in a
7+
/// `Vec`.
8+
///
9+
/// This `struct` is created by the [`peek_mut`] method on [`Vec`]. See
10+
/// its documentation for more.
11+
///
12+
/// [`peek_mut`]: Vec::peek_mut
13+
#[unstable(feature = "vec_peek_mut", issue = "122742")]
14+
pub struct PeekMut<'a, T> {
15+
vec: &'a mut Vec<T>,
16+
}
17+
18+
#[unstable(feature = "vec_peek_mut", issue = "122742")]
19+
impl<T: fmt::Debug> fmt::Debug for PeekMut<'_, T> {
20+
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
21+
f.debug_tuple("PeekMut").field(self.deref()).finish()
22+
}
23+
}
24+
25+
impl<'a, T> PeekMut<'a, T> {
26+
pub(crate) fn new(vec: &'a mut Vec<T>) -> Option<Self> {
27+
if vec.is_empty() { None } else { Some(Self { vec }) }
28+
}
29+
30+
/// Removes the peeked value from the vector and returns it.
31+
#[unstable(feature = "vec_peek_mut", issue = "122742")]
32+
pub fn pop(self) -> T {
33+
// SAFETY: PeekMut is only constructed if the vec is non-empty
34+
unsafe { self.vec.pop().unwrap_unchecked() }
35+
}
36+
}
37+
38+
#[unstable(feature = "vec_peek_mut", issue = "122742")]
39+
impl<'a, T> Deref for PeekMut<'a, T> {
40+
type Target = T;
41+
42+
fn deref(&self) -> &Self::Target {
43+
// SAFETY: PeekMut is only constructed if the vec is non-empty
44+
unsafe { self.vec.get_unchecked(self.vec.len() - 1) }
45+
}
46+
}
47+
48+
#[unstable(feature = "vec_peek_mut", issue = "122742")]
49+
impl<'a, T> DerefMut for PeekMut<'a, T> {
50+
fn deref_mut(&mut self) -> &mut Self::Target {
51+
let idx = self.vec.len() - 1;
52+
// SAFETY: PeekMut is only constructed if the vec is non-empty
53+
unsafe { self.vec.get_unchecked_mut(idx) }
54+
}
55+
}

library/alloctests/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@
4242
#![feature(trusted_random_access)]
4343
#![feature(try_reserve_kind)]
4444
#![feature(try_trait_v2)]
45+
#![feature(vec_peek_mut)]
4546
// tidy-alphabetical-end
4647
//
4748
// Language features:

library/alloctests/tests/vec.rs

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2698,6 +2698,17 @@ fn test_pop_if_mutates() {
26982698
assert_eq!(v, [2]);
26992699
}
27002700

2701+
#[test]
2702+
fn test_peek_mut() {
2703+
let mut vec = Vec::new();
2704+
assert!(vec.peek_mut().is_none());
2705+
vec.push(1);
2706+
vec.push(2);
2707+
assert_eq!(vec.peek_mut(), Some(2));
2708+
*vec.peek_mut() = 0;
2709+
assert_eq!(vec.peek_mut(), Some(0));
2710+
}
2711+
27012712
/// This assortment of tests, in combination with miri, verifies we handle UB on fishy arguments
27022713
/// in the stdlib. Draining and extending the allocation are fairly well-tested earlier, but
27032714
/// `vec.insert(usize::MAX, val)` once slipped by!

0 commit comments

Comments
 (0)