itertools/
peeking_take_while.rs

1use std::iter::Peekable;
2use crate::PutBack;
3#[cfg(feature = "use_alloc")]
4use crate::PutBackN;
5
6/// An iterator that allows peeking at an element before deciding to accept it.
7///
8/// See [`.peeking_take_while()`](crate::Itertools::peeking_take_while)
9/// for more information.
10///
11/// This is implemented by peeking adaptors like peekable and put back,
12/// but also by a few iterators that can be peeked natively, like the slice’s
13/// by reference iterator (`std::slice::Iter`).
14pub trait PeekingNext : Iterator {
15    /// Pass a reference to the next iterator element to the closure `accept`;
16    /// if `accept` returns true, return it as the next element,
17    /// else None.
18    fn peeking_next<F>(&mut self, accept: F) -> Option<Self::Item>
19        where F: FnOnce(&Self::Item) -> bool;
20}
21
22impl<I> PeekingNext for Peekable<I>
23    where I: Iterator,
24{
25    fn peeking_next<F>(&mut self, accept: F) -> Option<Self::Item>
26        where F: FnOnce(&Self::Item) -> bool
27    {
28        if let Some(r) = self.peek() {
29            if !accept(r) {
30                return None;
31            }
32        }
33        self.next()
34    }
35}
36
37impl<I> PeekingNext for PutBack<I>
38    where I: Iterator,
39{
40    fn peeking_next<F>(&mut self, accept: F) -> Option<Self::Item>
41        where F: FnOnce(&Self::Item) -> bool
42    {
43        if let Some(r) = self.next() {
44            if !accept(&r) {
45                self.put_back(r);
46                return None;
47            }
48            Some(r)
49        } else {
50            None
51        }
52    }
53}
54
55#[cfg(feature = "use_alloc")]
56impl<I> PeekingNext for PutBackN<I>
57    where I: Iterator,
58{
59    fn peeking_next<F>(&mut self, accept: F) -> Option<Self::Item>
60        where F: FnOnce(&Self::Item) -> bool
61    {
62        if let Some(r) = self.next() {
63            if !accept(&r) {
64                self.put_back(r);
65                return None;
66            }
67            Some(r)
68        } else {
69            None
70        }
71    }
72}
73
74/// An iterator adaptor that takes items while a closure returns `true`.
75///
76/// See [`.peeking_take_while()`](crate::Itertools::peeking_take_while)
77/// for more information.
78#[must_use = "iterator adaptors are lazy and do nothing unless consumed"]
79pub struct PeekingTakeWhile<'a, I: 'a, F>
80    where I: Iterator,
81{
82    iter: &'a mut I,
83    f: F,
84}
85
86impl<'a, I: 'a, F> std::fmt::Debug for PeekingTakeWhile<'a, I, F>
87where
88    I: Iterator + std::fmt::Debug,
89{
90    debug_fmt_fields!(PeekingTakeWhile, iter);
91}
92
93/// Create a `PeekingTakeWhile`
94pub fn peeking_take_while<I, F>(iter: &mut I, f: F) -> PeekingTakeWhile<I, F>
95    where I: Iterator,
96{
97    PeekingTakeWhile {
98        iter,
99        f,
100    }
101}
102
103impl<'a, I, F> Iterator for PeekingTakeWhile<'a, I, F>
104    where I: PeekingNext,
105          F: FnMut(&I::Item) -> bool,
106
107{
108    type Item = I::Item;
109    fn next(&mut self) -> Option<Self::Item> {
110        self.iter.peeking_next(&mut self.f)
111    }
112
113    fn size_hint(&self) -> (usize, Option<usize>) {
114        (0, self.iter.size_hint().1)
115    }
116}
117
118// Some iterators are so lightweight we can simply clone them to save their
119// state and use that for peeking.
120macro_rules! peeking_next_by_clone {
121    ([$($typarm:tt)*] $type_:ty) => {
122        impl<$($typarm)*> PeekingNext for $type_ {
123            fn peeking_next<F>(&mut self, accept: F) -> Option<Self::Item>
124                where F: FnOnce(&Self::Item) -> bool
125            {
126                let saved_state = self.clone();
127                if let Some(r) = self.next() {
128                    if !accept(&r) {
129                        *self = saved_state;
130                    } else {
131                        return Some(r)
132                    }
133                }
134                None
135            }
136        }
137    }
138}
139
140peeking_next_by_clone! { ['a, T] ::std::slice::Iter<'a, T> }
141peeking_next_by_clone! { ['a] ::std::str::Chars<'a> }
142peeking_next_by_clone! { ['a] ::std::str::CharIndices<'a> }
143peeking_next_by_clone! { ['a] ::std::str::Bytes<'a> }
144peeking_next_by_clone! { ['a, T] ::std::option::Iter<'a, T> }
145peeking_next_by_clone! { ['a, T] ::std::result::Iter<'a, T> }
146peeking_next_by_clone! { [T] ::std::iter::Empty<T> }
147#[cfg(feature = "use_alloc")]
148peeking_next_by_clone! { ['a, T] alloc::collections::linked_list::Iter<'a, T> }
149#[cfg(feature = "use_alloc")]
150peeking_next_by_clone! { ['a, T] alloc::collections::vec_deque::Iter<'a, T> }
151
152// cloning a Rev has no extra overhead; peekable and put backs are never DEI.
153peeking_next_by_clone! { [I: Clone + PeekingNext + DoubleEndedIterator]
154                         ::std::iter::Rev<I> }