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
use core::{fmt, iter};
use crate::iteration::{carry, peekable_exhaust};
use crate::Exhaust;
impl<T: Exhaust, const N: usize> Exhaust for [T; N] {
type Iter = ExhaustArray<T, N>;
type Factory = [T::Factory; N];
fn exhaust_factories() -> Self::Iter {
ExhaustArray {
state: [(); N].map(|()| peekable_exhaust::<T>()),
done_zero: false,
}
}
fn from_factory(factory: Self::Factory) -> Self {
factory.map(T::from_factory)
}
}
/// Iterator implementation of `[T; N]::exhaust()`.
pub struct ExhaustArray<T: Exhaust, const N: usize> {
/// Iterators for each element of the array.
///
/// Ideally we would not store any `Peekable` state for the last element, but that would require
/// the type `[iter::Peekable<T::Iter>; N - 1]`, which stable Rust does not yet allow.
state: [iter::Peekable<T::Iter>; N],
/// For iterators over `[T; 0]`, whether the sole value has been produced.
///
/// Ideally this would be stored only if N == 0, but that is not possible in stable Rust.
done_zero: bool,
}
impl<T, const N: usize> fmt::Debug for ExhaustArray<T, N>
where
T: Exhaust<Iter: fmt::Debug, Factory: fmt::Debug>,
{
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("ExhaustArray")
.field("state", &self.state)
.field("done_zero", &self.done_zero)
.finish()
}
}
impl<T: Exhaust, const N: usize> Clone for ExhaustArray<T, N> {
fn clone(&self) -> Self {
Self {
state: self.state.clone(),
done_zero: self.done_zero,
}
}
}
impl<T: Exhaust, const N: usize> Iterator for ExhaustArray<T, N> {
type Item = [T::Factory; N];
fn next(&mut self) -> Option<Self::Item> {
if N == 0 {
return if self.done_zero {
None
} else {
self.done_zero = true;
// This is just `Some([])` in disguise.
Some([(); N].map(|()| unreachable!("called zero times")))
};
}
// Check if we have a next item
let has_next = self
.state
.iter_mut()
.all(|value_iter| value_iter.peek().is_some());
if !has_next {
return None;
}
// Gather that next item.
// unwrap() cannot fail because we checked with peek().
let item: [<T as Exhaust>::Factory; N] = core::array::from_fn(|i| {
if i == N - 1 {
// Advance the "last digit".
self.state[i].next().unwrap()
} else {
// Don't advance the others
self.state[i].peek().unwrap().clone()
}
});
// "Carry": if the rightmost iterator is exhausted, advance the one to the left,
// and repeat for all but the leftmost. If the leftmost is exhausted, we'll stop
// on the next iteration.
for i in (1..N).rev() {
let (high, low) = &mut self.state.split_at_mut(i);
if !carry(high.last_mut().unwrap(), &mut low[0], peekable_exhaust::<T>) {
break;
}
}
Some(item)
}
}
impl<T: Exhaust, const N: usize> iter::FusedIterator for ExhaustArray<T, N> {}