iter_scanb/lib.rs
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114
#![doc = include_str!("../README.md")]
use core::{
fmt::{self, Debug},
iter::FusedIterator,
};
/// Like the [`Iterator::scan`], but use `B`, instead of `Option<B>`,
/// which can bring better [`size_hint`] and ergonomics.
///
/// At the same time,
/// it will also be able to implement [`ExactSizeIterator`] and [`FusedIterator`]
///
/// [`size_hint`]: Iterator::size_hint
pub trait IterScanB: Iterator + Sized {
/// An iterator adapter which, like [`Iterator::scan`],
/// but returns a value of `B` instead of `Option<B>`.
/// which can bring better [`size_hint`] and ergonomics.
///
/// At the same time,
/// it will also be able to implement [`ExactSizeIterator`] and [`FusedIterator`]
///
/// # Examples
/// ```
/// # use iter_scanb::IterScanB;
/// let a = [1, 2, 3, 4];
///
/// let mut iter = a.iter().scanb(1, |state, &x| {
/// *state *= x;
/// -*state
/// });
///
/// assert_eq!(iter.next(), Some(-1));
/// assert_eq!(iter.next(), Some(-2));
/// assert_eq!(iter.next(), Some(-6));
/// assert_eq!(iter.next(), Some(-24));
/// assert_eq!(iter.next(), None);
/// ```
///
/// [`size_hint`]: Iterator::size_hint
fn scanb<S, B, F>(self, init_state: S, f: F) -> ScanB<Self, S, F>
where F: FnMut(&mut S, Self::Item) -> B,
{
ScanB {
iter: self,
f,
state: init_state,
}
}
}
impl<I: Iterator> IterScanB for I {}
/// Create from [`IterScanB::scanb`]
#[must_use = "iterators are lazy and do nothing unless consumed"]
#[derive(Clone, Copy, PartialEq, Eq, Hash)]
pub struct ScanB<I, S, F> {
iter: I,
f: F,
state: S,
}
impl<I: Debug, S: Debug, F> Debug for ScanB<I, S, F> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("ScanB")
.field("iter", &self.iter)
.field("state", &self.state)
.finish()
}
}
impl<I, S, F, B> Iterator for ScanB<I, S, F>
where I: Iterator,
F: FnMut(&mut S, I::Item) -> B,
{
type Item = B;
fn next(&mut self) -> Option<Self::Item> {
self.iter.next()
.map(|ele| (self.f)(&mut self.state, ele))
}
// NOTE:
// Do not implement `nth`,
// otherwise it may not have been executed on every element
fn fold<B1, F1>(mut self, init: B1, mut f: F1) -> B1
where Self: Sized,
F1: FnMut(B1, Self::Item) -> B1,
{
self.iter.fold(init, |acc, ele| {
let ele = (self.f)(&mut self.state, ele);
f(acc, ele)
})
}
fn size_hint(&self) -> (usize, Option<usize>) {
self.iter.size_hint()
}
}
impl<I, S, F> FusedIterator for ScanB<I, S, F>
where I: FusedIterator,
F: for<'a> FnMut(&'a mut S, I::Item),
{
}
impl<I, S, F> ExactSizeIterator for ScanB<I, S, F>
where I: ExactSizeIterator,
F: for<'a> FnMut(&'a mut S, I::Item),
{
fn len(&self) -> usize {
self.iter.len()
}
}