exhaust/
iteration.rs

1//! Assistance for implementing exhaustive iterators.
2//!
3//! These functions were found to be repeatedly useful within the built-in implementations,
4//! and are provided publicly in the expectation that they will have more uses.
5
6use core::iter::Peekable;
7use core::{fmt, iter};
8
9use crate::Exhaust;
10
11/// Convenience alias for a Peekable Exhaustive Iterator, frequently used in iterator
12/// implementations.
13///
14/// Note that this iterator’s items are of type `T::Factory`, not `T`.
15pub type Pei<T> = Peekable<<T as Exhaust>::Iter>;
16
17/// Construct a [`Peekable`] exhaustive factory iterator.
18///
19/// Peekable iterators are useful for iterating over the product of multiple iterators.
20pub fn peekable_exhaust<T: Exhaust>() -> Pei<T> {
21    T::exhaust_factories().peekable()
22}
23
24/// Perform “carry” within a pair of peekable iterators.
25///
26/// That is, if `low` has no more elements, advance `high`, and replace `low`
27/// with a fresh iterator from the factory function.
28///
29/// Returns whether a carry occurred.
30///
31/// # Example
32///
33/// ```
34/// use exhaust::{Exhaust, iteration::carry};
35///
36/// // Setup
37/// let new_iter = || u8::exhaust().peekable();
38/// let mut high = new_iter();
39/// let mut low = new_iter();
40/// for _ in &mut low {} // advance to the end
41///
42/// // Perform a carry.
43/// assert_eq!([high.peek(), low.peek()], [Some(&0), None]);
44/// let carried = carry(&mut high, &mut low, new_iter);
45/// assert!(carried);
46/// assert_eq!([high.peek(), low.peek()], [Some(&1), Some(&0)]);
47///
48/// // If the low iterator has an element already, the iterators are unchanged.
49/// let carried = carry(&mut high, &mut low, new_iter);
50/// assert!(!carried);
51/// assert_eq!([high.peek(), low.peek()], [Some(&1), Some(&0)]);
52/// ```
53pub fn carry<I, J, F>(high: &mut Peekable<I>, low: &mut Peekable<J>, factory: F) -> bool
54where
55    I: Iterator,
56    J: Iterator,
57    F: FnOnce() -> Peekable<J>,
58{
59    if low.peek().is_none() {
60        *low = factory();
61        high.next();
62        true
63    } else {
64        false
65    }
66}
67
68#[test]
69fn carry_example() {}
70
71/// Given an iterator and a function of its elements that yields an iterator,
72/// produce tuples of the two iterators' results.
73#[derive(Clone)]
74#[doc(hidden)] // Public because exposed as an iterator type. Not yet recommended for use.
75pub struct FlatZipMap<I: Iterator, J: Iterator, O> {
76    outer_iterator: I,
77    inner: Option<(I::Item, J)>,
78    iter_fn: fn(&I::Item) -> J,
79    output_fn: fn(I::Item, J::Item) -> O,
80}
81
82impl<I, J, O> fmt::Debug for FlatZipMap<I, J, O>
83where
84    I: Iterator + fmt::Debug,
85    I::Item: fmt::Debug,
86    J: Iterator + fmt::Debug,
87{
88    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
89        f.debug_struct("FlatZipMap")
90            .field("outer_iterator", &self.outer_iterator)
91            .field("outer_item", &self.inner.as_ref().map(|i| &i.0))
92            .field("inner_iterator", &self.inner.as_ref().map(|i| &i.1))
93            .finish_non_exhaustive()
94    }
95}
96
97impl<I, J, O> FlatZipMap<I, J, O>
98where
99    I: Iterator,
100    J: Iterator,
101{
102    #[cfg_attr(not(feature = "std"), allow(dead_code))]
103    pub(crate) fn new(
104        outer_iterator: I,
105        iter_fn: fn(&I::Item) -> J,
106        output_fn: fn(I::Item, J::Item) -> O,
107    ) -> Self {
108        Self {
109            outer_iterator,
110            inner: None,
111            iter_fn,
112            output_fn,
113        }
114    }
115}
116
117impl<I, J, O> Iterator for FlatZipMap<I, J, O>
118where
119    I: Iterator,
120    I::Item: Clone,
121    J: Iterator,
122{
123    type Item = O;
124
125    fn next(&mut self) -> Option<Self::Item> {
126        loop {
127            match self.inner {
128                Some((ref i_item, ref mut j_iter)) => {
129                    if let Some(j_item) = j_iter.next() {
130                        return Some((self.output_fn)(i_item.clone(), j_item));
131                    }
132                    // If no items, try the outer iter.
133                    self.inner = None;
134                }
135                None => match self.outer_iterator.next() {
136                    Some(i_item) => {
137                        let j_iter = (self.iter_fn)(&i_item);
138                        self.inner = Some((i_item, j_iter));
139                    }
140                    None => return None,
141                },
142            }
143        }
144    }
145}
146
147impl<I, J, O> iter::FusedIterator for FlatZipMap<I, J, O>
148where
149    I: Iterator,
150    I::Item: Clone,
151    J: Iterator,
152{
153}