diff --git a/src/arr.rs b/src/arr.rs index aed4999205..8274a9cc36 100644 --- a/src/arr.rs +++ b/src/arr.rs @@ -26,30 +26,31 @@ pub type Inc = >::Output; #[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) )*; + (@count_ty) => { $crate::typenum::U0 }; + (@count_ty $val:expr$(, $vals:expr)* $(,)?) => { $crate::typenum::Add1<$crate::arr_impl!(@count_ty $($vals),*)> }; + ($T:ty; $($x:expr),*) => ({ + const __INPUT_LENGTH: usize = 0 $(+ $crate::arr_impl!(@replace_expr $x) )*; + type __OutputLength = $crate::arr_impl!(@count_ty $($x),*); #[inline(always)] - fn __do_transmute>(arr: [T; __ARR_LENGTH]) -> $crate::GenericArray { + const fn __do_transmute>(arr: [T; __INPUT_LENGTH]) -> $crate::GenericArray { unsafe { $crate::transmute(arr) } } - let _: [(); <$N as $crate::typenum::Unsigned>::USIZE] = [(); __ARR_LENGTH]; + const _: [(); <__OutputLength as $crate::typenum::Unsigned>::USIZE] = [(); __INPUT_LENGTH]; - __do_transmute::<$T, $N>([$($x as $T),*]) + __do_transmute::<$T, __OutputLength>([$($x as $T),*]) + }); + ($T:ty; $x:expr; $N: ty) => ({ + const __INPUT_LENGTH: usize = <$N as $crate::typenum::Unsigned>::USIZE; + + #[inline(always)] + const fn __do_transmute>(arr: [T; __INPUT_LENGTH]) -> $crate::GenericArray { + unsafe { $crate::transmute(arr) } + } + + __do_transmute::<$T, $N>([$x; __INPUT_LENGTH]) }); - ($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. @@ -60,7 +61,10 @@ macro_rules! arr { unsafe { $crate::transmute::<[$T; 0], $crate::GenericArray<$T, $crate::typenum::U0>>([]) } }); ($T:ty; $($x:expr),* $(,)*) => ( - $crate::arr_impl!($T; $crate::typenum::U0, [], [$($x),*]) + $crate::arr_impl!($T; $($x),*) + ); + ($T:ty; $x:expr; $N:ty) => ( + $crate::arr_impl!($T; $x; $N) ); ($($x:expr,)+) => (arr![$($x),+]); () => ("""Macro requires a type, e.g. `let array = arr![u32; 1, 2, 3];`") diff --git a/src/lib.rs b/src/lib.rs index f6a14e9df2..d3bde9ab85 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -639,9 +639,15 @@ where /// when the compiler can't prove equal sizes. #[inline] #[doc(hidden)] -pub unsafe fn transmute(a: A) -> B { +pub const unsafe fn transmute(a: A) -> B { + #[repr(C)] + union Union { + a: ManuallyDrop, + b: ManuallyDrop, + } + let a = ManuallyDrop::new(a); - ::core::ptr::read(&*a as *const A as *const B) + ManuallyDrop::into_inner(Union { a }.b) } #[cfg(test)] diff --git a/tests/arr.rs b/tests/arr.rs index c37b5d50f7..8553302132 100644 --- a/tests/arr.rs +++ b/tests/arr.rs @@ -25,3 +25,15 @@ fn with_trailing_comma() { let ar = arr![u8; 10, 20, 30, ]; assert_eq!(format!("{:x}", ar), "0a141e"); } + +#[test] +fn const_context() { + const AR: generic_array::GenericArray = arr![u8; 10, 20, 30]; + assert_eq!(format!("{:x}", AR), "0a141e"); +} + +#[test] +fn repeat_expression() { + let ar = arr![u8; 0xc0; typenum::U4]; + assert_eq!(format!("{:x}", ar), "c0c0c0c0"); +} \ No newline at end of file