relay_server/utils/
split_off.rs

1use itertools::Either;
2
3/// Splits off items from a vector matching a predicate.
4///
5/// Matching elements are returned in the second vector.
6pub fn split_off<T>(data: Vec<T>, mut f: impl FnMut(&T) -> bool) -> (Vec<T>, Vec<T>) {
7    split_off_map(data, |item| {
8        if f(&item) {
9            Either::Right(item)
10        } else {
11            Either::Left(item)
12        }
13    })
14}
15
16/// Splits off items from a vector matching a predicate and mapping the removed items.
17pub fn split_off_map<T, S>(data: Vec<T>, mut f: impl FnMut(T) -> Either<T, S>) -> (Vec<T>, Vec<S>) {
18    let mut right = Vec::new();
19
20    let left = data
21        .into_iter()
22        .filter_map(|item| match f(item) {
23            Either::Left(item) => Some(item),
24            Either::Right(p) => {
25                right.push(p);
26                None
27            }
28        })
29        .collect();
30
31    (left, right)
32}
33
34#[cfg(test)]
35mod tests {
36    use super::*;
37
38    #[test]
39    fn test_split_off() {
40        let data = vec!["apple", "apple", "orange"];
41
42        let (apples, oranges) = split_off(data, |item| *item == "orange");
43        assert_eq!(apples, vec!["apple", "apple"]);
44        assert_eq!(oranges, vec!["orange"]);
45    }
46
47    #[test]
48    fn test_split_off_map() {
49        let data = vec!["apple", "apple", "orange"];
50
51        let (apples, oranges) = split_off_map(data, |item| {
52            if item != "orange" {
53                Either::Left(item)
54            } else {
55                Either::Right(item)
56            }
57        });
58        assert_eq!(apples, vec!["apple", "apple"]);
59        assert_eq!(oranges, vec!["orange"]);
60    }
61}