Skip to content

Commit b38ee5e

Browse files
Rollup merge of #142046 - Qelxiros:122742-vec_peek_mut, r=cuviper
add Vec::peek_mut Tracking issue: #122742
2 parents efc55fa + 9d19cbe commit b38ee5e

File tree

6 files changed

+107
-2
lines changed

6 files changed

+107
-2
lines changed

library/alloc/src/vec/mod.rs

Lines changed: 32 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,33 @@ 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 last item in the vector, or
739+
/// `None` if it is empty.
740+
///
741+
/// # Examples
742+
///
743+
/// Basic usage:
744+
///
745+
/// ```
746+
/// #![feature(vec_peek_mut)]
747+
/// let mut vec = Vec::new();
748+
/// assert!(vec.peek_mut().is_none());
749+
///
750+
/// vec.push(1);
751+
/// vec.push(5);
752+
/// vec.push(2);
753+
/// assert_eq!(vec.last(), Some(&2));
754+
/// if let Some(mut val) = vec.peek_mut() {
755+
/// *val = 0;
756+
/// }
757+
/// assert_eq!(vec.last(), Some(&0));
758+
/// ```
759+
#[inline]
760+
#[unstable(feature = "vec_peek_mut", issue = "122742")]
761+
pub fn peek_mut(&mut self) -> Option<PeekMut<'_, T>> {
762+
PeekMut::new(self)
763+
}
732764
}
733765

734766
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/tests/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@
4040
#![feature(vec_deque_truncate_front)]
4141
#![feature(unique_rc_arc)]
4242
#![feature(macro_metavar_expr_concat)]
43+
#![feature(vec_peek_mut)]
4344
#![allow(internal_features)]
4445
#![deny(fuzzy_provenance_casts)]
4546
#![deny(unsafe_op_in_unsafe_fn)]

library/alloctests/tests/vec.rs

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2698,6 +2698,23 @@ 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+
if let Some(mut p) = vec.peek_mut() {
2708+
assert_eq!(*p, 2);
2709+
*p = 0;
2710+
assert_eq!(*p, 0);
2711+
p.pop();
2712+
assert_eq!(vec.len(), 1);
2713+
} else {
2714+
unreachable!()
2715+
}
2716+
}
2717+
27012718
/// This assortment of tests, in combination with miri, verifies we handle UB on fishy arguments
27022719
/// in the stdlib. Draining and extending the allocation are fairly well-tested earlier, but
27032720
/// `vec.insert(usize::MAX, val)` once slipped by!

tests/ui/borrowck/issue-47646.stderr

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ LL | println!("{:?}", heap);
1111
| ^^^^ immutable borrow occurs here
1212
...
1313
LL | };
14-
| - ... and the mutable borrow might be used here, when that temporary is dropped and runs the destructor for type `(Option<PeekMut<'_, i32>>, ())`
14+
| - ... and the mutable borrow might be used here, when that temporary is dropped and runs the destructor for type `(Option<std::collections::binary_heap::PeekMut<'_, i32>>, ())`
1515
|
1616
= note: this error originates in the macro `$crate::format_args_nl` which comes from the expansion of the macro `println` (in Nightly builds, run with -Z macro-backtrace for more info)
1717

tests/ui/borrowck/issue-85581.stderr

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ LL | Some(_) => { heap.pop(); },
1010
| ^^^^ second mutable borrow occurs here
1111
...
1212
LL | }
13-
| - ... and the first borrow might be used here, when that temporary is dropped and runs the destructor for type `Option<PeekMut<'_, i32>>`
13+
| - ... and the first borrow might be used here, when that temporary is dropped and runs the destructor for type `Option<std::collections::binary_heap::PeekMut<'_, i32>>`
1414

1515
error: aborting due to 1 previous error
1616

0 commit comments

Comments
 (0)