blob: 0b64e1d7ad64aad860b32786585c49d0bd8f8064 [file] [log] [blame]
Jakub Kotura425e552020-12-21 17:28:15 +01001use std::iter::Fuse;
2use std::collections::VecDeque;
3use crate::size_hint;
4use crate::PeekingNext;
5
6/// See [`multipeek()`](../fn.multipeek.html) for more information.
7#[derive(Clone, Debug)]
8pub struct MultiPeek<I>
9 where I: Iterator
10{
11 iter: Fuse<I>,
12 buf: VecDeque<I::Item>,
13 index: usize,
14}
15
16/// An iterator adaptor that allows the user to peek at multiple `.next()`
17/// values without advancing the base iterator.
18pub fn multipeek<I>(iterable: I) -> MultiPeek<I::IntoIter>
19 where I: IntoIterator
20{
21 MultiPeek {
22 iter: iterable.into_iter().fuse(),
23 buf: VecDeque::new(),
24 index: 0,
25 }
26}
27
28impl<I> MultiPeek<I>
29 where I: Iterator
30{
31 /// Reset the peeking “cursor”
32 pub fn reset_peek(&mut self) {
33 self.index = 0;
34 }
35}
36
37impl<I: Iterator> MultiPeek<I> {
38 /// Works exactly like `.next()` with the only difference that it doesn't
39 /// advance itself. `.peek()` can be called multiple times, to peek
40 /// further ahead.
41 pub fn peek(&mut self) -> Option<&I::Item> {
42 let ret = if self.index < self.buf.len() {
43 Some(&self.buf[self.index])
44 } else {
45 match self.iter.next() {
46 Some(x) => {
47 self.buf.push_back(x);
48 Some(&self.buf[self.index])
49 }
50 None => return None,
51 }
52 };
53
54 self.index += 1;
55 ret
56 }
57}
58
59impl<I> PeekingNext for MultiPeek<I>
60 where I: Iterator,
61{
62 fn peeking_next<F>(&mut self, accept: F) -> Option<Self::Item>
63 where F: FnOnce(&Self::Item) -> bool
64 {
65 if self.buf.is_empty() {
66 if let Some(r) = self.peek() {
67 if !accept(r) { return None }
68 }
69 } else {
70 if let Some(r) = self.buf.get(0) {
71 if !accept(r) { return None }
72 }
73 }
74 self.next()
75 }
76}
77
78impl<I> Iterator for MultiPeek<I>
79 where I: Iterator
80{
81 type Item = I::Item;
82
83 fn next(&mut self) -> Option<I::Item> {
84 self.index = 0;
85 if self.buf.is_empty() {
86 self.iter.next()
87 } else {
88 self.buf.pop_front()
89 }
90 }
91
92 fn size_hint(&self) -> (usize, Option<usize>) {
93 size_hint::add_scalar(self.iter.size_hint(), self.buf.len())
94 }
95}
96
97// Same size
98impl<I> ExactSizeIterator for MultiPeek<I>
99 where I: ExactSizeIterator
100{}
101
102