Skip to main content

const_tools/
unzip.rs

1/// Unzips an array of tuples into multiple arrays in const contexts.
2///
3/// It is possible to assign the result of the unzipped expression inside of the macro invocation to avoid the need for
4/// [`crate::destructure`].
5///
6/// # Examples
7///
8/// ```
9/// use const_tools::unzip;
10///
11/// const fn unzip_pairs<A, B, const N: usize>(arr: [(A, B); N]) -> ([A; N], [B; N]) {
12///     unzip!(let (a, b) = arr);
13///     (a, b)
14/// }
15/// ```
16#[macro_export]
17macro_rules! unzip {
18    (let ($($oap:pat_param),* $(,)?) = $($unzip_arg:tt)*) => {
19        $crate::__zip_left!(
20            [$(($oap, ))*]
21            [(oa0, oi0) (oa1, oi1) (oa2, oi2) (oa3, oi3) (oa4, oi4) (oa5, oi5) (oa6, oi6) (oa7, oi7) (oa8, oi8) (oa9, oi9) (oa10, oi10) (oa11, oi11)]
22            "unsupported number of outputs"
23            $crate::__unzip__parse_unzip_arg!([$($unzip_arg)*] <>)
24        )
25    };
26}
27
28#[doc(hidden)]
29#[macro_export]
30macro_rules! __unzip__parse_unzip_arg {
31    // [iae] [(oap, oa, oi)]
32    ([map!($($map_args:tt)*)] $($rest:tt)*) => {
33        $crate::__map__parse!([$($map_args)*] $crate::__unzip__parse_map_body!(<> $($rest)*))
34    };
35    ([$iae:expr] [$(($oap:pat_param, $oa:ident, $oi:ident))*]) => {
36        $crate::__unzip__expand!([
37            $crate::destructure!(let ($($oi),*) = ii);
38        ] [($iae, ii, ia)] [$(($oap, $oa, $oi))*])
39    };
40}
41
42#[doc(hidden)]
43#[macro_export]
44macro_rules! __unzip__parse_map_body {
45    // [map_body] [(iae, iip, ia)] [(oap, oa, oi)]
46    ([{ $($body:tt)* }] $($rest:tt)*) => {
47        $crate::__unzip__parse_map_body_block!([$($body)*] [] $($rest)*)
48    };
49    ([($($oie:expr),* $(,)?)] $i:tt [$(($oap:pat_param, $oa:ident, $oi:ident))*]) => {
50        $crate::__unzip__expand!([] $i [$(($oap, $oa, $oie))*])
51    };
52    ([$body:expr] $i:tt [$(($oap:pat_param, $oa:ident, $oi:ident))*]) => {
53        $crate::__unzip__expand!([
54            let item = $body;
55            $crate::destructure!(let ($($oi),*) = item);
56        ] $i [$(($oap, $oa, $oi))*])
57    };
58}
59
60#[doc(hidden)]
61#[macro_export]
62macro_rules! __unzip__parse_map_body_block {
63    // [map_body_block_stmts] [body_acc] [(iae, iip, ia)] [(oap, oa, oi)]
64    ([] [$($body:tt)*] $i:tt [$(($oap:pat_param, $oa:ident, $oi:ident))*]) => {
65        $crate::__unzip__expand!([
66            let item = {
67                $($body)*
68            };
69            $crate::destructure!(let ($($oi),*) = item);
70        ] $i [$(($oap, $oa, $oi))*])
71    };
72    ([($($oie:expr),* $(,)?)] [$($body:tt)*] $i:tt [$(($oap:pat_param, $oa:ident, $oi:ident))*]) => {
73        $crate::__unzip__expand!([$($body)*] $i [$(($oap, $oa, $oie))*])
74    };
75    ([$head:tt $($tail:tt)*] [$($body:tt)*] $($rest:tt)*) => {
76        $crate::__unzip__parse_map_body_block!([$($tail)*] [$($body)* $head] $($rest)*)
77    };
78}
79
80#[doc(hidden)]
81#[macro_export]
82macro_rules! __unzip__expand {
83    // [body]  [(iae, iip, ia)] [(oap, oa, oie)]
84    ([$($body:tt)*] [$(($iae:expr, $iip:pat_param, $ia:ident))*] [$(($oap:pat_param, $oa:ident, $oie:expr))*]) => {
85        $(
86            let mut $oa = $crate::__maybe_uninit_array_uninit();
87        )*
88        $(
89            let $ia = ::core::mem::ManuallyDrop::new($iae);
90            let $ia = $crate::__manually_drop_inner_ref(&$ia);
91        )*
92        let len = $crate::__same_len!($(&$oa,)* $(&$ia,)*);
93        let mut index = 0;
94        #[deny(unreachable_code)]
95        while index < len {
96            $(
97                let $iip = unsafe { ::core::ptr::read(&$ia[index]) };
98            )*
99            $($body)*
100            $(
101                $oa[index].write($oie);
102            )*
103            index += 1;
104        }
105        assert!(
106            index == len,
107            "break is not allowed because a value must be written into every array element"
108        );
109        $(
110            let $oap = unsafe { $crate::__maybe_uninit_array_assume_init($oa) };
111        )*
112    };
113}