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}