itertools/
peeking_take_while.rs

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