Skip to main content

yui_core/ext/
digits.rs

1//! [`IntoDigits`]: decompose an integer into its base-10 digits.
2
3/// Decompose a non-negative integer into its base-10 digits.
4///
5/// See: <https://en.wikipedia.org/wiki/Positional_notation>
6pub trait IntoDigits: Sized {
7    type Digit;
8
9    /// Iterator over digits, most-significant first.
10    fn into_digits(self) -> impl Iterator<Item = Self::Digit> {
11        let mut v: Vec<_> = self.into_rev_digits().collect();
12        v.reverse();
13        v.into_iter()
14    }
15
16    /// Iterator over digits, least-significant first.
17    fn into_rev_digits(self) -> impl Iterator<Item = Self::Digit> {
18        let mut v: Vec<_> = self.into_digits().collect();
19        v.reverse();
20        v.into_iter()
21    }
22}
23
24macro_rules! impl_into_digits {
25    ($t: ty, $d: ty) => {
26        impl IntoDigits for $t {
27            type Digit = $d;
28            fn into_rev_digits(self) -> impl Iterator<Item = $d> {
29                std::iter::successors(
30                    Some(self),
31                    |&n| (n >= 10).then(|| n / 10),
32                ).map(|n| (n % 10) as $d)
33            }
34        }
35    };
36}
37
38impl_into_digits!(usize, u8);
39
40#[cfg(test)]
41mod tests {
42    use super::*;
43
44    #[test]
45    fn usize() {
46        let a = 123456789;
47        assert_eq!(a.into_digits().collect::<Vec<_>>(), vec![1,2,3,4,5,6,7,8,9]);
48        assert_eq!(a.into_rev_digits().collect::<Vec<_>>(), vec![9,8,7,6,5,4,3,2,1]);
49    }
50
51    #[test]
52    fn zero() {
53        assert_eq!(0usize.into_digits().collect::<Vec<_>>(), vec![0]);
54        assert_eq!(0usize.into_rev_digits().collect::<Vec<_>>(), vec![0]);
55    }
56}