Skip to content

Commit 30e31f2

Browse files
committed
utils: Add a method to split an iterator
Signed-off-by: Colin Walters <[email protected]>
1 parent 4b17ac0 commit 30e31f2

File tree

1 file changed

+94
-0
lines changed

1 file changed

+94
-0
lines changed

utils/src/lib.rs

Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,3 +6,97 @@ mod command;
66
mod tracing_util;
77
pub use command::*;
88
pub use tracing_util::*;
9+
10+
/// Given an iterator that's clonable, split it into two iterators
11+
/// at a given maximum number of elements.
12+
pub fn iterator_split<I>(
13+
it: I,
14+
max: usize,
15+
) -> (impl Iterator<Item = I::Item>, impl Iterator<Item = I::Item>)
16+
where
17+
I: Iterator + Clone,
18+
{
19+
let rest = it.clone();
20+
(it.take(max), rest.skip(max))
21+
}
22+
23+
/// Given an iterator that's clonable, split off the first N elements
24+
/// at the pivot point. If the iterator would be empty, return None.
25+
/// Return the count of the remainder.
26+
pub fn iterator_split_nonempty_rest_count<I>(
27+
it: I,
28+
max: usize,
29+
) -> Option<(impl Iterator<Item = I::Item>, usize)>
30+
where
31+
I: Iterator + Clone,
32+
{
33+
let rest = it.clone();
34+
let mut it = it.peekable();
35+
if it.peek().is_some() {
36+
Some((it.take(max), rest.skip(max).count()))
37+
} else {
38+
None
39+
}
40+
}
41+
42+
#[cfg(test)]
43+
mod tests {
44+
use super::*;
45+
46+
#[test]
47+
fn test_it_split() {
48+
let a: &[&str] = &[];
49+
for v in [0, 1, 5] {
50+
let (first, rest) = iterator_split(a.iter(), v);
51+
assert_eq!(first.count(), 0);
52+
assert_eq!(rest.count(), 0);
53+
}
54+
let a = &["foo"];
55+
for v in [1, 5] {
56+
let (first, rest) = iterator_split(a.iter(), v);
57+
assert_eq!(first.count(), 1);
58+
assert_eq!(rest.count(), 0);
59+
}
60+
let (first, rest) = iterator_split(a.iter(), 1);
61+
assert_eq!(first.count(), 1);
62+
assert_eq!(rest.count(), 0);
63+
let a = &["foo", "bar", "baz", "blah", "other"];
64+
let (first, rest) = iterator_split(a.iter(), 2);
65+
assert_eq!(first.count(), 2);
66+
assert_eq!(rest.count(), 3);
67+
}
68+
69+
#[test]
70+
fn test_split_empty_iterator() {
71+
let a: &[&str] = &[];
72+
for v in [0, 1, 5] {
73+
assert!(iterator_split_nonempty_rest_count(a.iter(), v).is_none());
74+
}
75+
}
76+
77+
#[test]
78+
fn test_split_nonempty_iterator() {
79+
let a = &["foo"];
80+
81+
let Some((elts, 1)) = iterator_split_nonempty_rest_count(a.iter(), 0) else {
82+
panic!()
83+
};
84+
assert_eq!(elts.count(), 0);
85+
86+
let Some((elts, 0)) = iterator_split_nonempty_rest_count(a.iter(), 1) else {
87+
panic!()
88+
};
89+
assert_eq!(elts.count(), 1);
90+
91+
let Some((elts, 0)) = iterator_split_nonempty_rest_count(a.iter(), 5) else {
92+
panic!()
93+
};
94+
assert_eq!(elts.count(), 1);
95+
96+
let a = &["foo", "bar", "baz", "blah", "other"];
97+
let Some((elts, 3)) = iterator_split_nonempty_rest_count(a.iter(), 2) else {
98+
panic!()
99+
};
100+
assert_eq!(elts.count(), 2);
101+
}
102+
}

0 commit comments

Comments
 (0)