Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
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
54 changes: 27 additions & 27 deletions library/alloc/src/vec/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -760,33 +760,6 @@ impl<T> Vec<T> {
unsafe { Self::from_parts_in(ptr, length, capacity, Global) }
}

/// Returns a mutable reference to the last item in the vector, or
/// `None` if it is empty.
///
/// # Examples
///
/// Basic usage:
///
/// ```
/// #![feature(vec_peek_mut)]
/// 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)
}

/// Decomposes a `Vec<T>` into its raw components: `(pointer, length, capacity)`.
///
/// Returns the raw pointer to the underlying data, the length of
Expand Down Expand Up @@ -2747,6 +2720,33 @@ impl<T, A: Allocator> Vec<T, A> {
if predicate(last) { self.pop() } else { None }
}

/// Returns a mutable reference to the last item in the vector, or
/// `None` if it is empty.
///
/// # Examples
///
/// Basic usage:
///
/// ```
/// #![feature(vec_peek_mut)]
/// 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, A>> {
PeekMut::new(self)
}

/// Moves all the elements of `other` into `self`, leaving `other` empty.
///
/// # Panics
Expand Down
22 changes: 14 additions & 8 deletions library/alloc/src/vec/peek_mut.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
use core::ops::{Deref, DerefMut};

use super::Vec;
use crate::alloc::{Allocator, Global};
use crate::fmt;

/// Structure wrapping a mutable reference to the last item in a
Expand All @@ -11,19 +12,23 @@ use crate::fmt;
///
/// [`peek_mut`]: Vec::peek_mut
#[unstable(feature = "vec_peek_mut", issue = "122742")]
pub struct PeekMut<'a, T> {
vec: &'a mut Vec<T>,
pub struct PeekMut<
'a,
T,
#[unstable(feature = "allocator_api", issue = "32838")] A: Allocator = Global,
> {
vec: &'a mut Vec<T, A>,
}

#[unstable(feature = "vec_peek_mut", issue = "122742")]
impl<T: fmt::Debug> fmt::Debug for PeekMut<'_, T> {
impl<T: fmt::Debug, A: Allocator> fmt::Debug for PeekMut<'_, T, A> {
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> {
impl<'a, T, A: Allocator> PeekMut<'a, T, A> {
pub(super) fn new(vec: &'a mut Vec<T, A>) -> Option<Self> {
if vec.is_empty() { None } else { Some(Self { vec }) }
}

Expand All @@ -36,17 +41,18 @@ impl<'a, T> PeekMut<'a, T> {
}

#[unstable(feature = "vec_peek_mut", issue = "122742")]
impl<'a, T> Deref for PeekMut<'a, T> {
impl<'a, T, A: Allocator> Deref for PeekMut<'a, T, A> {
type Target = T;

fn deref(&self) -> &Self::Target {
let idx = self.vec.len() - 1;
// SAFETY: PeekMut is only constructed if the vec is non-empty
unsafe { self.vec.get_unchecked(self.vec.len() - 1) }
unsafe { self.vec.get_unchecked(idx) }
}
}

#[unstable(feature = "vec_peek_mut", issue = "122742")]
impl<'a, T> DerefMut for PeekMut<'a, T> {
impl<'a, T, A: Allocator> DerefMut for PeekMut<'a, T, A> {
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
Expand Down
19 changes: 10 additions & 9 deletions library/alloctests/tests/vec.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2643,15 +2643,16 @@ fn test_peek_mut() {
assert!(vec.peek_mut().is_none());
vec.push(1);
vec.push(2);
if let Some(mut p) = vec.peek_mut() {
assert_eq!(*p, 2);
*p = 0;
assert_eq!(*p, 0);
PeekMut::pop(p);
assert_eq!(vec.len(), 1);
} else {
unreachable!()
}
let mut p = vec.peek_mut().unwrap();
assert_eq!(*p, 2);
*p = 0;
assert_eq!(*p, 0);
drop(p);
assert_eq!(vec, vec![1, 0]);
let p = vec.peek_mut().unwrap();
let p = PeekMut::pop(p);
assert_eq!(p, 0);
assert_eq!(vec, vec![1]);
}

/// This assortment of tests, in combination with miri, verifies we handle UB on fishy arguments
Expand Down
Loading