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