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
}