Skip to main content

const_tools/
map.rs

1/// Maps a function over arrays in const contexts.
2///
3/// # Examples
4///
5/// ```
6/// use const_tools::map;
7///
8/// struct Wrap<T>(T);
9///
10/// const fn wrap_all<T, const N: usize>(value: [T; N]) -> [Wrap<T>; N] {
11///     map!(value, Wrap)
12/// }
13/// ```
14#[macro_export]
15macro_rules! map {
16    ($($map_args:tt)*) => {
17        $crate::__map__parse!([$($map_args)*] $crate::__map__expand!(<>))
18    };
19}
20
21#[doc(hidden)]
22#[macro_export]
23macro_rules! __map__parse {
24    // [args] [cb]
25    ([zip!($($iae:expr),* $(,)?), |($($iip:pat_param),* $(,)?)| $($body:tt)*] $($cb:tt)*) => {
26        $crate::__zip_left!(
27            [$(($iae, $iip, ))*]
28            [(ia0) (ia1) (ia2) (ia3) (ia4) (ia5) (ia6) (ia7) (ia8) (ia9) (ia10) (ia11)]
29            "unsupported number of inputs"
30            $($cb)*([$($body)*] <>)
31        )
32    };
33    ([zip!($($iae:expr),* $(,)?), $fn:expr] $($cb:tt)*) => {
34        $crate::__zip_left!(
35            [$(($iae, ))*]
36            [(ii0, ia0) (ii1, ia1) (ii2, ia2) (ii3, ia3) (ii4, ia4) (ii5, ia5) (ii6, ia6) (ii7, ia7) (ii8, ia8) (ii9, ia9) (ii10, ia10) (ii11, ia11)]
37            "unsupported number of inputs"
38            $crate::__map__parse_fn!([$fn] <> $($cb)*)
39        )
40    };
41    ([$iae:expr, |$iip:pat_param| $($body:tt)*] $($cb:tt)*) => {
42        $crate::__call!($($cb)*([$($body)*] [($iae, $iip, ia0)]))
43    };
44    ([$iae:expr, $fn:expr]  $($cb:tt)*) => {
45        $crate::__call!($($cb)*([$fn(ii)] [($iae, ii, ia)]))
46    };
47}
48
49#[doc(hidden)]
50#[macro_export]
51macro_rules! __map__parse_fn {
52    // [fn] [(iae, ii, ia)]
53    ([$fn:expr] [$(($iae:expr, $ii:ident, $ia:ident))*] $($cb:tt)*) => {
54        $crate::__call!($($cb)*([$fn(($($ii,)*))] [$(($iae, $ii, $ia))*]))
55    };
56}
57
58#[doc(hidden)]
59#[macro_export]
60macro_rules! __map__expand {
61    // [body] [(iae, iip, ia)]
62    ([$body:expr] [$(($iae:expr, $iip:pat_param, $ia:ident))*]) => {{
63        let mut oa = $crate::__maybe_uninit_array_uninit();
64        $(
65            let $ia = ::core::mem::ManuallyDrop::new($iae);
66            let $ia = $crate::__manually_drop_inner_ref(&$ia);
67        )*
68        let len = $crate::__same_len!(&oa $(,$ia)*);
69        let mut index = 0;
70        #[deny(unreachable_code)]
71        while index < len {
72            $(
73                let $iip = unsafe { ::core::ptr::read(&$ia[index]) };
74            )*
75            oa[index].write($body);
76            index += 1;
77        }
78        assert!(
79            index == len,
80            "break is not allowed because a value must be written into every array element"
81        );
82        unsafe { $crate::__maybe_uninit_array_assume_init(oa) }
83    }};
84}