1 //! Implementation for `arr!` macro.
2 
3 use super::ArrayLength;
4 use core::ops::Add;
5 use typenum::U1;
6 
7 /// Helper trait for `arr!` macro
8 pub trait AddLength<T, N: ArrayLength<T>>: ArrayLength<T> {
9     /// Resulting length
10     type Output: ArrayLength<T>;
11 }
12 
13 impl<T, N1, N2> AddLength<T, N2> for N1
14 where
15     N1: ArrayLength<T> + Add<N2>,
16     N2: ArrayLength<T>,
17     <N1 as Add<N2>>::Output: ArrayLength<T>,
18 {
19     type Output = <N1 as Add<N2>>::Output;
20 }
21 
22 /// Helper type for `arr!` macro
23 pub type Inc<T, U> = <U as AddLength<T, U1>>::Output;
24 
25 #[doc(hidden)]
26 #[macro_export]
27 macro_rules! arr_impl {
28     (@replace_expr $e:expr) => { 1 };
29     ($T:ty; $N:ty, [$($x:expr),*], []) => ({
30         const __ARR_LENGTH: usize = 0 $(+ $crate::arr_impl!(@replace_expr $x) )*;
31 
32         #[inline(always)]
33         fn __do_transmute<T, N: $crate::ArrayLength<T>>(arr: [T; __ARR_LENGTH]) -> $crate::GenericArray<T, N> {
34             unsafe { $crate::transmute(arr) }
35         }
36 
37         let _: [(); <$N as $crate::typenum::Unsigned>::USIZE] = [(); __ARR_LENGTH];
38 
39         __do_transmute::<$T, $N>([$($x as $T),*])
40     });
41     ($T:ty; $N:ty, [], [$x1:expr]) => (
42         $crate::arr_impl!($T; $crate::arr::Inc<$T, $N>, [$x1], [])
43     );
44     ($T:ty; $N:ty, [], [$x1:expr, $($x:expr),+]) => (
45         $crate::arr_impl!($T; $crate::arr::Inc<$T, $N>, [$x1], [$($x),+])
46     );
47     ($T:ty; $N:ty, [$($y:expr),+], [$x1:expr]) => (
48         $crate::arr_impl!($T; $crate::arr::Inc<$T, $N>, [$($y),+, $x1], [])
49     );
50     ($T:ty; $N:ty, [$($y:expr),+], [$x1:expr, $($x:expr),+]) => (
51         $crate::arr_impl!($T; $crate::arr::Inc<$T, $N>, [$($y),+, $x1], [$($x),+])
52     );
53 }
54 
55 /// Macro allowing for easy generation of Generic Arrays.
56 /// Example: `let test = arr![u32; 1, 2, 3];`
57 #[macro_export]
58 macro_rules! arr {
59     ($T:ty; $(,)*) => ({
60         unsafe { $crate::transmute::<[$T; 0], $crate::GenericArray<$T, $crate::typenum::U0>>([]) }
61     });
62     ($T:ty; $($x:expr),* $(,)*) => (
63         $crate::arr_impl!($T; $crate::typenum::U0, [], [$($x),*])
64     );
65     ($($x:expr,)+) => (arr![$($x),+]);
66     () => ("""Macro requires a type, e.g. `let array = arr![u32; 1, 2, 3];`")
67 }
68 
69 mod doctests_only {
70     ///
71     /// # With ellision
72     ///
73     /// Testing that lifetimes aren't transmuted when they're ellided.
74     ///
75     /// ```compile_fail
76     /// #[macro_use] extern crate generic_array;
77     /// fn main() {
78     ///    fn unsound_lifetime_extension<'a, A>(a: &'a A) -> &'static A {
79     ///        arr![&A; a][0]
80     ///    }
81     /// }
82     /// ```
83     ///
84     /// ```rust
85     /// #[macro_use] extern crate generic_array;
86     /// fn main() {
87     ///    fn unsound_lifetime_extension<'a, A>(a: &'a A) -> &'a A {
88     ///        arr![&A; a][0]
89     ///    }
90     /// }
91     /// ```
92     ///
93     /// # Without ellision
94     ///
95     /// Testing that lifetimes aren't transmuted when they're specified explicitly.
96     ///
97     /// ```compile_fail
98     /// #[macro_use] extern crate generic_array;
99     /// fn main() {
100     ///    fn unsound_lifetime_extension<'a, A>(a: &'a A) -> &'static A {
101     ///        arr![&'a A; a][0]
102     ///    }
103     /// }
104     /// ```
105     ///
106     /// ```compile_fail
107     /// #[macro_use] extern crate generic_array;
108     /// fn main() {
109     ///    fn unsound_lifetime_extension<'a, A>(a: &'a A) -> &'static A {
110     ///        arr![&'static A; a][0]
111     ///    }
112     /// }
113     /// ```
114     ///
115     /// ```rust
116     /// #[macro_use] extern crate generic_array;
117     /// fn main() {
118     ///    fn unsound_lifetime_extension<'a, A>(a: &'a A) -> &'a A {
119     ///        arr![&'a A; a][0]
120     ///    }
121     /// }
122     /// ```
123     #[allow(dead_code)]
124     pub enum DocTests {}
125 }
126