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}