exhaust/impls/
core_primitive.rs

1use core::{fmt, iter};
2
3use crate::iteration::{carry, peekable_exhaust};
4use crate::patterns::{
5    delegate_factory_and_iter, factory_is_self, impl_newtype_generic, impl_via_array,
6    impl_via_range,
7};
8use crate::Exhaust;
9
10impl Exhaust for () {
11    type Iter = iter::Once<()>;
12    fn exhaust_factories() -> Self::Iter {
13        iter::once(())
14    }
15    factory_is_self!();
16}
17
18// Implement single-element tuples in the same way we implement other generic containers.
19impl_newtype_generic!(T: [], (T,), |x| (x,));
20
21// Generates tuple implementations from 2 to 12 items.
22// 12 was chosen as the same size the standard library offers.
23exhaust_macros::impl_exhaust_for_tuples!(12);
24
25impl_via_array!(bool, [false, true]);
26
27impl_via_range!(char, '\x00', char::MAX);
28impl_via_range!(i8, i8::MIN, i8::MAX);
29impl_via_range!(u8, u8::MIN, u8::MAX);
30impl_via_range!(i16, i16::MIN, i16::MAX);
31impl_via_range!(u16, u16::MIN, u16::MAX);
32impl_via_range!(i32, i32::MIN, i32::MAX);
33impl_via_range!(u32, u32::MIN, u32::MAX);
34// i64 and larger sizes are not implemented because it is not feasible to exhaust them.
35/// Note: The floats produced include many `NaN`s (all unequal in representation).
36impl Exhaust for f32 {
37    delegate_factory_and_iter!(u32);
38
39    fn from_factory(factory: Self::Factory) -> Self {
40        f32::from_bits(factory)
41    }
42}
43
44impl<T: Exhaust, const N: usize> Exhaust for [T; N] {
45    type Iter = ExhaustArray<T, N>;
46    type Factory = [T::Factory; N];
47    fn exhaust_factories() -> Self::Iter {
48        ExhaustArray {
49            state: [(); N].map(|()| peekable_exhaust::<T>()),
50            done_zero: false,
51        }
52    }
53    fn from_factory(factory: Self::Factory) -> Self {
54        factory.map(T::from_factory)
55    }
56}
57
58/// Iterator implementation of `[T; N]::exhaust()`.
59pub struct ExhaustArray<T: Exhaust, const N: usize> {
60    state: [iter::Peekable<T::Iter>; N],
61    done_zero: bool,
62}
63
64impl<T, const N: usize> fmt::Debug for ExhaustArray<T, N>
65where
66    T: Exhaust<Iter: fmt::Debug, Factory: fmt::Debug>,
67{
68    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
69        f.debug_struct("ExhaustArray")
70            .field("state", &self.state)
71            .field("done_zero", &self.done_zero)
72            .finish()
73    }
74}
75
76impl<T: Exhaust, const N: usize> Clone for ExhaustArray<T, N> {
77    fn clone(&self) -> Self {
78        Self {
79            state: self.state.clone(),
80            done_zero: self.done_zero,
81        }
82    }
83}
84
85impl<T: Exhaust, const N: usize> Iterator for ExhaustArray<T, N> {
86    type Item = [T::Factory; N];
87
88    fn next(&mut self) -> Option<Self::Item> {
89        if N == 0 {
90            return if self.done_zero {
91                None
92            } else {
93                self.done_zero = true;
94                // This is just `Some([])` in disguise
95                Some([(); N].map(|()| unreachable!()))
96            };
97        }
98
99        // Check if we have a next item
100        let has_next = self
101            .state
102            .iter_mut()
103            .all(|value_iter| value_iter.peek().is_some());
104
105        if !has_next {
106            return None;
107        }
108
109        // Gather that next item.
110        // unwrap() cannot fail because we checked with peek().
111        let mut i = 0;
112        let item = [(); N].map(|()| {
113            let element = if i == N - 1 {
114                // Advance the "last digit".
115                self.state[i].next().unwrap()
116            } else {
117                // Don't advance the others
118                self.state[i].peek().unwrap().clone()
119            };
120            i += 1;
121            element
122        });
123
124        // "Carry": if the rightmost iterator is exhausted, advance the one to the left,
125        // and repeat for all but the leftmost. If the leftmost is exhausted, we'll stop
126        // on the next iteration.
127        for i in (1..N).rev() {
128            let (high, low) = &mut self.state.split_at_mut(i);
129            if !carry(high.last_mut().unwrap(), &mut low[0], peekable_exhaust::<T>) {
130                break;
131            }
132        }
133
134        Some(item)
135    }
136}
137
138impl<T: Exhaust, const N: usize> iter::FusedIterator for ExhaustArray<T, N> {}