diff --git a/library/alloc/src/vec/mod.rs b/library/alloc/src/vec/mod.rs index ebdb86f98a857..694b7b2df08fe 100644 --- a/library/alloc/src/vec/mod.rs +++ b/library/alloc/src/vec/mod.rs @@ -2173,9 +2173,37 @@ impl Vec { panic!("removal index (is {index}) should be < len (is {len})"); } + match self.try_remove(index) { + Some(elem) => elem, + None => assert_failed(index, self.len()), + } + } + + /// Remove and return the element at position `index` within the vector, + /// shifting all elements after it to the left, or [`None`] if it does not + /// exist. + /// + /// Note: Because this shifts over the remaining elements, it has a + /// worst-case performance of *O*(*n*). If you'd like to remove + /// elements from the beginning of the `Vec`, consider using + /// [`VecDeque::pop_front`] instead. + /// + /// [`VecDeque::pop_front`]: crate::collections::VecDeque::pop_front + /// + /// # Examples + /// + /// ``` + /// #![feature(vec_try_remove)] + /// let mut v = vec![1, 2, 3]; + /// assert_eq!(v.try_remove(0), Some(1)); + /// assert_eq!(v.try_remove(2), None); + /// ``` + #[unstable(feature = "vec_try_remove", issue = "146954")] + #[rustc_confusables("delete", "take", "remove")] + pub fn try_remove(&mut self, index: usize) -> Option { let len = self.len(); if index >= len { - assert_failed(index, len); + return None; } unsafe { // infallible @@ -2191,7 +2219,7 @@ impl Vec { ptr::copy(ptr.add(1), ptr, len - index - 1); } self.set_len(len - 1); - ret + Some(ret) } } diff --git a/library/alloctests/tests/lib.rs b/library/alloctests/tests/lib.rs index 8c3ce156f3c1d..cba9883e148e2 100644 --- a/library/alloctests/tests/lib.rs +++ b/library/alloctests/tests/lib.rs @@ -41,6 +41,7 @@ #![feature(unique_rc_arc)] #![feature(macro_metavar_expr_concat)] #![feature(vec_peek_mut)] +#![feature(vec_try_remove)] #![allow(internal_features)] #![deny(fuzzy_provenance_casts)] #![deny(unsafe_op_in_unsafe_fn)] diff --git a/library/alloctests/tests/vec.rs b/library/alloctests/tests/vec.rs index 33a34daccbfd2..ea334ab0f143a 100644 --- a/library/alloctests/tests/vec.rs +++ b/library/alloctests/tests/vec.rs @@ -630,6 +630,21 @@ fn test_swap_remove_empty() { vec.swap_remove(0); } +#[test] +fn test_try_remove() { + let mut vec = vec![1, 2, 3]; + // We are attempting to remove vec[0] which contains 1 + assert_eq!(vec.try_remove(0), Some(1)); + // Now `vec` looks like: [2, 3] + // We will now try to remove vec[2] which does not exist + // This should return `None` + assert_eq!(vec.try_remove(2), None); + + // We will try the same thing with an empty vector + let mut v: Vec = vec![]; + assert!(v.try_remove(0).is_none()); +} + #[test] fn test_move_items() { let vec = vec![1, 2, 3];