unroll_fn/
lib.rs

1#![feature(min_specialization)]
2
3struct Const<const N: usize>;
4
5trait UnrollImpl {
6    fn unroll<F: FnMut(usize)>(f: F);
7}
8
9impl<const N: usize> UnrollImpl for Const<N> {
10    default fn unroll<F: FnMut(usize)>(_: F) {
11        unimplemented!();
12    }
13}
14
15macro_rules! unroll_impl {
16    ($n:expr) => {
17        impl UnrollImpl for Const<$n> {
18            #[inline(always)]
19            fn unroll<F: FnMut(usize)>(mut f: F) {
20                seq_macro::seq!(N in 0..$n{ f(N); });
21            }
22        }
23    };
24}
25
26impl UnrollImpl for Const<0> {
27    fn unroll<F: FnMut(usize)>(_: F) {}
28}
29seq_macro::seq!(N in 1.. =256 {unroll_impl!(N);});
30
31/// Call the function `f` `N` times. This is guaranteed to get unrolled.
32/// Values of `N` up to `256` are supported.
33#[inline(always)]
34pub fn unroll<const N: usize, F: FnMut(usize)>(f: F) {
35    Const::<N>::unroll(f);
36}
37
38#[cfg(test)]
39mod tests {
40    use super::*;
41
42    #[test]
43    fn test_unroll() {
44        let mut a = 0;
45        unroll::<24, _>(|i| a += i);
46        assert_eq!(a, 12 * 23);
47    }
48}