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