1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
//! Extract elements from a vector based on supplied criteria
//!
//! *Project by [SnS Development](https://gitlab.com/SnSDev)*
//!
//! # Problem
//!
//! Need to filter some elements out of an existing Vector through a mutable
//! borrow
//!
//! # Solution
//!
//! A trait implemented on `Vec<T>` with 2 functions `remove_if` and
//! `swap_remove_if` that iterate over elements, runs a supplied closure,
//! and removes elements where the closure returns [true].
//!
//! # Example
//! ```
//! use vec_remove_if::VecRemoveIf;
//! let mut v = vec![1, 12, 3, 14, 5, 16, 7, 18];
//!
//! assert_eq!(
//!     vec![12, 14, 16, 18],
//!     v.remove_if(|e| e > &10)
//! );
//! assert_eq!(
//!     vec![1, 3, 5, 7],
//!     v
//! );
//! ```
#![warn(missing_docs)]

/// Add [Self::remove_if] and [Self::swap_remove_if] to [Vec]
pub trait VecRemoveIf<T> {
    /// Run [Vec::remove] on each element in a vec when `closure` returns true
    ///
    /// # Example
    ///
    /// ```
    /// use vec_remove_if::VecRemoveIf;
    /// let mut v = vec![1, 2, 3, 4, 5, 6, 7, 8];
    ///
    /// assert_eq!(
    ///     vec![1, 2, 3],
    ///     v.remove_if(|e| e < &4)
    /// );
    /// assert_eq!(
    ///     vec![4, 5, 6, 7, 8],
    ///     v
    /// );
    /// ```
    fn remove_if<F: Fn(&T) -> bool>(&mut self, closure: F) -> Vec<T>;

    /// Run [Vec::swap_remove] on each element in a vec when `closure` returns true
    ///
    /// [Self::swap_remove_if] is more efficient, but does not preserve the
    /// element order of the vector (See [Vec::swap_remove]).
    ///
    /// # Example
    ///
    /// ```
    /// use vec_remove_if::VecRemoveIf;
    /// let mut v = vec![1, 2, 3, 4, 5, 6, 7, 8];
    ///
    /// assert_eq!(
    ///     vec![1, 2, 3],
    ///     v.swap_remove_if(|e| e < &4)
    /// );
    /// assert_eq!(
    ///     vec![8, 7, 6, 4, 5],
    ///     v
    ///  );
    /// ```
    fn swap_remove_if<F: Fn(&T) -> bool>(&mut self, closure: F) -> Vec<T>;
}

impl<T> VecRemoveIf<T> for Vec<T> {
    fn remove_if<F: Fn(&T) -> bool>(&mut self, closure: F) -> Vec<T> {
        common(self, closure, &mut Vec::remove)
    }

    fn swap_remove_if<F: Fn(&T) -> bool>(&mut self, closure: F) -> Vec<T> {
        common(self, closure, &mut Vec::swap_remove)
    }
}

fn common<T, F: Fn(&T) -> bool, A: FnMut(&mut Vec<T>, usize) -> T>(
    v: &mut Vec<T>,
    closure: F,
    action: &mut A,
) -> Vec<T> {
    let mut i = 0;
    let mut r = Vec::new();

    while i < v.len() {
        if closure(&v[i]) {
            r.push(action(v, i))
        } else {
            i += 1;
        }
    }

    r
}