1//! Implementation for `arr!` macro.
2
3use super::ArrayLength;
4use core::ops::Add;
5use typenum::U1;
6
7/// Helper trait for `arr!` macro
8pub trait AddLength<T, N: ArrayLength<T>>: ArrayLength<T> {
9 /// Resulting length
10 type Output: ArrayLength<T>;
11}
12
13impl<T, N1, N2> AddLength<T, N2> for N1
14where
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
23pub type Inc<T, U> = <U as AddLength<T, U1>>::Output;
24
25#[doc(hidden)]
26#[macro_export]
27macro_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]
58macro_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
69mod 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