divisors/
lib.rs

1pub trait Divisors: Sized {
2    fn divisors(self) -> impl Iterator<Item = Self>;
3}
4
5macro_rules! impl_uint {
6    ( $($ty:ty)* ) => { $(
7        impl Divisors for $ty {
8            fn divisors(self) -> impl Iterator<Item = Self> {
9                let n = self;
10                std::iter::successors(
11                    (n >= 1).then_some((1, true)),
12                    move |&(i, asc)| {
13                        if asc {
14                            if let Some(j) = (i + 1..)
15                                .take_while(|j| j * j <= n)
16                                .find(|j| n % j == 0)
17                            {
18                                return Some((j, true));
19                            } else if n / i != i {
20                                return Some((i, false));
21                            }
22                        }
23                        let j = (1..i).rev().find(|&j| n % j == 0)?;
24                        Some((j, false))
25                    },
26                )
27                .map(move |(i, asc)| if asc { i } else { n / i })
28            }
29        }
30    )* };
31}
32
33impl_uint! { u8 u16 u32 u64 u128 usize }
34
35#[test]
36fn sanity_check() {
37    assert!(0_u32.divisors().eq(None));
38
39    for n in 1_u32..=10000 {
40        let expected = (1..=n).filter(|i| n % i == 0);
41        let actual = n.divisors();
42        assert!(actual.eq(expected));
43    }
44}