use std::iter::FusedIterator;
pub struct Peekable<I: Iterator> {
pub(crate) iter: I,
peeked: Option<Option<I::Item>>,
}
impl<I: Iterator> Peekable<I> {
pub(crate) fn new(iter: I) -> Peekable<I> {
Peekable { iter, peeked: None }
}
}
impl<I: Iterator> Iterator for Peekable<I> {
type Item = I::Item;
#[inline]
fn next(&mut self) -> Option<I::Item> {
match self.peeked.take() {
Some(v) => v,
None => self.iter.next(),
}
}
#[inline]
fn count(mut self) -> usize {
match self.peeked.take() {
Some(None) => 0,
Some(Some(_)) => 1 + self.iter.count(),
None => self.iter.count(),
}
}
#[inline]
fn nth(&mut self, n: usize) -> Option<I::Item> {
match self.peeked.take() {
Some(None) => None,
Some(v @ Some(_)) if n == 0 => v,
Some(Some(_)) => self.iter.nth(n - 1),
None => self.iter.nth(n),
}
}
#[inline]
fn last(mut self) -> Option<I::Item> {
let peek_opt = match self.peeked.take() {
Some(None) => return None,
Some(v) => v,
None => None,
};
self.iter.last().or(peek_opt)
}
#[inline]
fn size_hint(&self) -> (usize, Option<usize>) {
let peek_len = match self.peeked {
Some(None) => return (0, Some(0)),
Some(Some(_)) => 1,
None => 0,
};
let (lo, hi) = self.iter.size_hint();
let lo = lo.saturating_add(peek_len);
let hi = match hi {
Some(x) => x.checked_add(peek_len),
None => None,
};
(lo, hi)
}
#[inline]
fn fold<Acc, Fold>(self, init: Acc, mut fold: Fold) -> Acc
where
Fold: FnMut(Acc, Self::Item) -> Acc,
{
let acc = match self.peeked {
Some(None) => return init,
Some(Some(v)) => fold(init, v),
None => init,
};
self.iter.fold(acc, fold)
}
}
impl<I> DoubleEndedIterator for Peekable<I>
where
I: DoubleEndedIterator,
{
#[inline]
fn next_back(&mut self) -> Option<Self::Item> {
match self.peeked.as_mut() {
Some(v @ Some(_)) => self.iter.next_back().or_else(|| v.take()),
Some(None) => None,
None => self.iter.next_back(),
}
}
#[inline]
fn rfold<Acc, Fold>(self, init: Acc, mut fold: Fold) -> Acc
where
Fold: FnMut(Acc, Self::Item) -> Acc,
{
match self.peeked {
Some(None) => init,
Some(Some(v)) => {
let acc = self.iter.rfold(init, &mut fold);
fold(acc, v)
}
None => self.iter.rfold(init, fold),
}
}
}
impl<I: ExactSizeIterator> ExactSizeIterator for Peekable<I> {}
impl<I: FusedIterator> FusedIterator for Peekable<I> {}
impl<I: Iterator> Peekable<I> {
#[inline]
pub fn peek(&mut self) -> Option<&I::Item> {
let iter = &mut self.iter;
self.peeked.get_or_insert_with(|| iter.next()).as_ref()
}
}