      1
      2
      3
      4
      5
      6
      7
      8
      9
     10
     11
     12
     13
     14
     15
     16
     17
     18
     19
     20
     21
     22
     23
     24
     25
     26
     27
     28
     29
     30
     31
     32
     33
     34
     35
     36
     37
     38
     39
     40
     41
     42
     43
     44
     45
     46
     47
     48
     49
     50
     51
     52
     53
     54
     55
     56
     57
     58
     59
     60
     61
     62
     63
     64
     65
     66
     67
     68
     69
     70
     71
     72
     73
     74
     75
     76
     77
     78
     79
     80
     81
     82
     83
     84
     85
     86
     87
     88
     89
     90
     91
     92
     93
     94
     95
     96
     97
     98
     99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125

    //! Implementation for `arr!` macro.

    use super::ArrayLength;
    use core::ops::Add;
    use typenum::U1;

    /// Helper trait for `arr!` macro
    pub trait AddLength<T, N: ArrayLength<T>>: ArrayLength<T> {
        /// Resulting length
        type Output: ArrayLength<T>;
    }

    impl<T, N1, N2> AddLength<T, N2> for N1
    where
        N1: ArrayLength<T> + Add<N2>,
        N2: ArrayLength<T>,
        <N1 as Add<N2>>::Output: ArrayLength<T>,
    {
        type Output = <N1 as Add<N2>>::Output;
    }

    /// Helper type for `arr!` macro
    pub type Inc<T, U> = <U as AddLength<T, U1>>::Output;

    #[doc(hidden)]
    #[macro_export]
    macro_rules! arr_impl {
        (@replace_expr $e:expr) => { 1 };
        ($T:ty; $N:ty, [$($x:expr),*], []) => ({
            const __ARR_LENGTH: usize = 0 $(+ $crate::arr_impl!(@replace_expr $x) )*;

            #[inline(always)]
            fn __do_transmute<T, N: $crate::ArrayLength<T>>(arr: [T; __ARR_LENGTH]) -> $crate::GenericArray<T, N> {
                unsafe { $crate::transmute(arr) }
            }

            let _: [(); <$N as $crate::typenum::Unsigned>::USIZE] = [(); __ARR_LENGTH];

            __do_transmute::<$T, $N>([$($x as $T),*])
        });
        ($T:ty; $N:ty, [], [$x1:expr]) => (
            $crate::arr_impl!($T; $crate::arr::Inc<$T, $N>, [$x1], [])
        );
        ($T:ty; $N:ty, [], [$x1:expr, $($x:expr),+]) => (
            $crate::arr_impl!($T; $crate::arr::Inc<$T, $N>, [$x1], [$($x),+])
        );
        ($T:ty; $N:ty, [$($y:expr),+], [$x1:expr]) => (
            $crate::arr_impl!($T; $crate::arr::Inc<$T, $N>, [$($y),+, $x1], [])
        );
        ($T:ty; $N:ty, [$($y:expr),+], [$x1:expr, $($x:expr),+]) => (
            $crate::arr_impl!($T; $crate::arr::Inc<$T, $N>, [$($y),+, $x1], [$($x),+])
        );
    }

    /// Macro allowing for easy generation of Generic Arrays.
    /// Example: `let test = arr![u32; 1, 2, 3];`
    #[macro_export]
    macro_rules! arr {
        ($T:ty; $(,)*) => ({
            unsafe { $crate::transmute::<[$T; 0], $crate::GenericArray<$T, $crate::typenum::U0>>([]) }
        });
        ($T:ty; $($x:expr),* $(,)*) => (
            $crate::arr_impl!($T; $crate::typenum::U0, [], [$($x),*])
        );
        ($($x:expr,)+) => (arr![$($x),+]);
        () => ("""Macro requires a type, e.g. `let array = arr![u32; 1, 2, 3];`")
    }

    mod doctests_only {
        ///
        /// # With ellision
        ///
        /// Testing that lifetimes aren't transmuted when they're ellided.
        ///
        /// ```compile_fail
        /// #[macro_use] extern crate generic_array;
        /// fn main() {
        ///    fn unsound_lifetime_extension<'a, A>(a: &'a A) -> &'static A {
        ///        arr![&A; a][0]
        ///    }
        /// }
        /// ```
        ///
        /// ```rust
        /// #[macro_use] extern crate generic_array;
        /// fn main() {
        ///    fn unsound_lifetime_extension<'a, A>(a: &'a A) -> &'a A {
        ///        arr![&A; a][0]
        ///    }
        /// }
        /// ```
        ///
        /// # Without ellision
        ///
        /// Testing that lifetimes aren't transmuted when they're specified explicitly.
        ///
        /// ```compile_fail
        /// #[macro_use] extern crate generic_array;
        /// fn main() {
        ///    fn unsound_lifetime_extension<'a, A>(a: &'a A) -> &'static A {
        ///        arr![&'a A; a][0]
        ///    }
        /// }
        /// ```
        ///
        /// ```compile_fail
        /// #[macro_use] extern crate generic_array;
        /// fn main() {
        ///    fn unsound_lifetime_extension<'a, A>(a: &'a A) -> &'static A {
        ///        arr![&'static A; a][0]
        ///    }
        /// }
        /// ```
        ///
        /// ```rust
        /// #[macro_use] extern crate generic_array;
        /// fn main() {
        ///    fn unsound_lifetime_extension<'a, A>(a: &'a A) -> &'a A {
        ///        arr![&'a A; a][0]
        ///    }
        /// }
        /// ```
        #[allow(dead_code)]
        pub enum DocTests {}
    }