Skip to content

Commit

Permalink
Unrolled build for rust-lang#123107
Browse files Browse the repository at this point in the history
Rollup merge of rust-lang#123107 - avandesa:vec_pop_if, r=joboet

Implement `Vec::pop_if`

This PR adds `Vec::pop_if` to the public API, behind the `vec_pop_if` feature.

```rust
impl<T> Vec<T> {
    pub fn pop_if<F>(&mut self, f: F) -> Option<T>
        where F: FnOnce(&mut T) -> bool;
}
```

Tracking issue: rust-lang#122741

## Open questions

- [ ] Should the first unit test be split up?
- [ ] I don't see any guidance on ordering of methods in impl blocks, should I move the method elsewhere?
  • Loading branch information
rust-timer committed Mar 27, 2024
2 parents 435b525 + 07d3806 commit e638197
Show file tree
Hide file tree
Showing 4 changed files with 57 additions and 0 deletions.
1 change: 1 addition & 0 deletions library/alloc/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -170,6 +170,7 @@
#![feature(unicode_internals)]
#![feature(unsize)]
#![feature(utf8_chunks)]
#![feature(vec_pop_if)]
// tidy-alphabetical-end
//
// Language features:
Expand Down
25 changes: 25 additions & 0 deletions library/alloc/src/vec/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2058,6 +2058,31 @@ impl<T, A: Allocator> Vec<T, A> {
}
}

/// Removes and returns the last element in a vector if the predicate
/// returns `true`, or [`None`] if the predicate returns false or the vector
/// is empty.
///
/// # Examples
///
/// ```
/// #![feature(vec_pop_if)]
///
/// let mut vec = vec![1, 2, 3, 4];
/// let pred = |x: &mut i32| *x % 2 == 0;
///
/// assert_eq!(vec.pop_if(pred), Some(4));
/// assert_eq!(vec, [1, 2, 3]);
/// assert_eq!(vec.pop_if(pred), None);
/// ```
#[unstable(feature = "vec_pop_if", issue = "122741")]
pub fn pop_if<F>(&mut self, f: F) -> Option<T>
where
F: FnOnce(&mut T) -> bool,
{
let last = self.last_mut()?;
if f(last) { self.pop() } else { None }
}

/// Moves all the elements of `other` into `self`, leaving `other` empty.
///
/// # Panics
Expand Down
1 change: 1 addition & 0 deletions library/alloc/tests/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@
#![feature(strict_provenance)]
#![feature(drain_keep_rest)]
#![feature(local_waker)]
#![feature(vec_pop_if)]
#![allow(internal_features)]
#![deny(fuzzy_provenance_casts)]
#![deny(unsafe_op_in_unsafe_fn)]
Expand Down
30 changes: 30 additions & 0 deletions library/alloc/tests/vec.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2644,6 +2644,36 @@ fn test_vec_from_array_mut_ref() {
assert_eq!(Vec::from(&mut [1, 2, 3]), vec![1, 2, 3]);
}

#[test]
fn test_pop_if() {
let mut v = vec![1, 2, 3, 4];
let pred = |x: &mut i32| *x % 2 == 0;

assert_eq!(v.pop_if(pred), Some(4));
assert_eq!(v, [1, 2, 3]);

assert_eq!(v.pop_if(pred), None);
assert_eq!(v, [1, 2, 3]);
}

#[test]
fn test_pop_if_empty() {
let mut v = Vec::<i32>::new();
assert_eq!(v.pop_if(|_| true), None);
assert!(v.is_empty());
}

#[test]
fn test_pop_if_mutates() {
let mut v = vec![1];
let pred = |x: &mut i32| {
*x += 1;
false
};
assert_eq!(v.pop_if(pred), None);
assert_eq!(v, [2]);
}

/// 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

0 comments on commit e638197

Please sign in to comment.