#![no_std]
#![forbid(
clippy::as_conversions,
clippy::cast_ptr_alignment,
missing_docs,
trivial_casts,
unsafe_code
)]
use core::fmt;
pub trait PeekableExt<I>: Iterator
where
I: Iterator,
{
fn peeking_take_while<P>(&mut self, predicate: P) -> PeekingTakeWhile<'_, I, P>
where
P: FnMut(&Self::Item) -> bool;
}
impl<I: Iterator> PeekableExt<I> for core::iter::Peekable<I> {
#[inline]
fn peeking_take_while<P>(&mut self, predicate: P) -> PeekingTakeWhile<'_, I, P>
where
P: FnMut(&Self::Item) -> bool,
{
PeekingTakeWhile {
iter: self,
predicate,
}
}
}
pub struct PeekingTakeWhile<'a, I, P>
where
I: Iterator,
{
pub(crate) iter: &'a mut core::iter::Peekable<I>,
pub(crate) predicate: P,
}
impl<I, P> fmt::Debug for PeekingTakeWhile<'_, I, P>
where
I: Iterator + fmt::Debug,
I::Item: fmt::Debug,
{
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("PeekingTakeWhile")
.field("iter", &self.iter)
.finish()
}
}
impl<I, P> Iterator for PeekingTakeWhile<'_, I, P>
where
I: Iterator,
P: FnMut(&I::Item) -> bool,
{
type Item = I::Item;
#[inline]
fn next(&mut self) -> Option<Self::Item> {
self.iter.next_if(&mut self.predicate)
}
#[inline]
fn size_hint(&self) -> (usize, Option<usize>) {
(0, self.iter.size_hint().1)
}
#[inline]
fn fold<B, F>(mut self, mut accum: B, mut f: F) -> B
where
F: FnMut(B, I::Item) -> B,
{
while let Some(x) = self.iter.next_if(&mut self.predicate) {
accum = f(accum, x);
}
accum
}
}
#[cfg(test)]
mod tests {
use crate::PeekableExt;
#[test]
fn basic() {
let mut it0 = (1..11).peekable();
let a: u32 = it0.peeking_take_while(|&i| i < 5).sum();
let b: u32 = it0.sum();
assert_eq!(a, 10);
assert_eq!(b, 45);
}
#[test]
fn basic_fused() {
let mut it0 = (1..11).peekable();
let a: u32 = it0.peeking_take_while(|&i| i < 5).fuse().sum();
let b: u32 = it0.sum();
assert_eq!(a, 10);
assert_eq!(b, 45);
}
#[test]
fn not_fused() {
let mut it0 = (0..10).peekable();
let mut ax = true;
let mut it1 = it0.peeking_take_while(|_| {
ax = !ax;
ax
});
assert!(it1.next().is_none());
assert_eq!(it1.next(), Some(0));
assert!(it1.next().is_none());
assert_eq!(it1.next(), Some(1));
assert_eq!(ax, true);
}
#[test]
fn fused() {
let mut it0 = (0..10).peekable();
let mut ax = true;
let mut it1 = it0
.peeking_take_while(|_| {
ax = !ax;
ax
})
.fuse();
assert!(it1.next().is_none());
assert!(it1.next().is_none());
assert_eq!(ax, false);
}
}