integer_iterator/
lib.rs

1/// A simple wrapper type over the integer type `T` because `Rust` reserves the right to implement
2/// `Iterator` for them.
3///
4/// # Example
5///
6/// ```rust
7/// # use integer_iterator::DigitIterator;
8/// # pub fn main() -> Result<(), Box<dyn std::error::Error>> {
9/// let mut y = DigitIterator(30u32);
10/// assert_eq!(y.next(), Some(0));
11/// assert_eq!(y.next(), Some(3));
12/// assert_eq!(y.next(), None);
13/// # Ok(())
14/// # }
15/// ```
16///
17pub struct DigitIterator<T>(pub T, bool); // TODO :: Where T is an integer?
18
19/// Extends a type `T` with the ability to become a [`DigitIterator`].
20pub trait IntoDigits<T> {
21    fn digits(self) -> DigitIterator<T>;
22}
23
24macro_rules! impl_digit_positive {
25    ($T:ty) => {
26        impl IntoDigits<$T> for $T {
27            fn digits(self) -> DigitIterator<$T> {
28                DigitIterator(self, self == 0)
29            }
30        }
31
32        impl Iterator for DigitIterator<$T> {
33            type Item = u8;
34
35            fn next(&mut self) -> Option<Self::Item> {
36                if self.1 {
37                    self.1 = false;
38                    Some(0)
39                } else if self.0 != 0 {
40                    let remainder = (self.0 % (10 as $T)) as Self::Item;
41                    self.0 /= (10 as $T);
42                    Some(remainder)
43                } else {
44                    None
45                }
46            }
47        }
48    };
49}
50
51macro_rules! impl_digit_negative {
52    ($T:ty) => {
53        impl IntoDigits<$T> for $T {
54            fn digits(self) -> DigitIterator<$T> {
55                DigitIterator(-self, self == 0)
56            }
57        }
58
59        impl Iterator for DigitIterator<$T> {
60            type Item = u8;
61
62            fn next(&mut self) -> Option<Self::Item> {
63                if self.1 {
64                    self.1 = false;
65                    Some(0)
66                } else if self.0 != 0 {
67                    let remainder = (self.0 % (10 as $T)) as Self::Item;
68                    self.0 /= (10 as $T);
69                    Some(remainder)
70                } else {
71                    None
72                }
73            }
74        }
75    };
76}
77
78impl_digit_positive!(u8);
79impl_digit_positive!(u16);
80impl_digit_positive!(u32);
81impl_digit_positive!(u64);
82impl_digit_positive!(u128);
83
84impl_digit_negative!(i8);
85impl_digit_negative!(i16);
86impl_digit_negative!(i32);
87impl_digit_negative!(i64);
88impl_digit_negative!(i128);
89
90#[test]
91fn test_all_numbers() {
92    for x in u128::MIN..10000u128 {
93        let length = x
94            .digits()
95            .enumerate()
96            .map(|(idx, _)| idx + 1)
97            .last()
98            .unwrap();
99        assert_eq!(length, x.to_string().len());
100    }
101
102    for x in 0..-10000i128 {
103        let length = x
104            .digits()
105            .enumerate()
106            .map(|(idx, _)| idx + 1)
107            .last()
108            .unwrap();
109        assert_eq!(length, x.to_string().len());
110    }
111}