]>
Commit | Line | Data |
---|---|---|
1 | ||
2 | use std::iter::Peekable; | |
3 | use PutBack; | |
4 | #[cfg(feature = "use_std")] | |
5 | use 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`). | |
15 | pub 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 | ||
23 | impl<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 | ||
38 | impl<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")] | |
57 | impl<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"] | |
80 | pub 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 | |
88 | pub 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 | ||
97 | impl<'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. | |
115 | macro_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 | ||
135 | peeking_next_by_clone! { ['a, T] ::std::slice::Iter<'a, T> } | |
136 | peeking_next_by_clone! { ['a] ::std::str::Chars<'a> } | |
137 | peeking_next_by_clone! { ['a] ::std::str::CharIndices<'a> } | |
138 | peeking_next_by_clone! { ['a] ::std::str::Bytes<'a> } | |
139 | peeking_next_by_clone! { ['a, T] ::std::option::Iter<'a, T> } | |
140 | peeking_next_by_clone! { ['a, T] ::std::result::Iter<'a, T> } | |
141 | peeking_next_by_clone! { [T] ::std::iter::Empty<T> } | |
142 | #[cfg(feature = "use_std")] | |
143 | peeking_next_by_clone! { ['a, T] ::std::collections::linked_list::Iter<'a, T> } | |
144 | #[cfg(feature = "use_std")] | |
145 | peeking_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. | |
148 | peeking_next_by_clone! { [I: Clone + PeekingNext + DoubleEndedIterator] | |
149 | ::std::iter::Rev<I> } |