iter_utils/
stop_once.rs

1//! Iterator adapter that yields items until a predicate matches, inclusive.
2
3pub struct StopOnce<I, P> {
4    iter: Option<I>,
5    is_last: P,
6}
7
8impl<I: Iterator, P: FnMut(&I::Item) -> bool> Iterator for StopOnce<I, P> {
9    type Item = I::Item;
10
11    fn next(&mut self) -> Option<Self::Item> {
12        let item = self.iter.as_mut()?.next()?;
13        if (self.is_last)(&item) {
14            self.iter = None;
15        }
16        Some(item)
17    }
18}
19
20pub trait Stopper: Iterator
21where
22    Self: Sized,
23{
24    /// Like `Iterator::take_while`, but additionally yields the terminal item.
25    fn stop_once<P: FnMut(&Self::Item) -> bool>(self, predicate: P) -> StopOnce<Self, P>;
26}
27
28impl<I: Iterator> Stopper for I {
29    fn stop_once<P: FnMut(&Self::Item) -> bool>(self, predicate: P) -> StopOnce<Self, P> {
30        StopOnce {
31            iter: Some(self),
32            is_last: predicate,
33        }
34    }
35}
36
37#[cfg(test)]
38mod tests {
39    use super::*;
40
41    #[test]
42    fn stop_once_includes_terminal() {
43        let items: Vec<_> = (1..10).stop_once(|&x| x == 5).collect();
44        assert_eq!(items, vec![1, 2, 3, 4, 5]);
45    }
46
47    #[test]
48    fn stop_once_empty_if_first_matches() {
49        let items: Vec<_> = (1..10).stop_once(|&x| x == 1).collect();
50        assert_eq!(items, vec![1]);
51    }
52
53    #[test]
54    fn stop_once_all_if_none_match() {
55        let items: Vec<_> = (1..5).stop_once(|&x| x == 10).collect();
56        assert_eq!(items, vec![1, 2, 3, 4]);
57    }
58}