That’s your claim.

The [[u8;4];2] case is sound because of the way arrays are laid out in memory.

The elements in an array, [T; N], will be laid out sequentially with no padding when size_of::<T>() == align_of::<T>(), so it’s fine to transmute it that way. See Arrays and Slices in the unsafe code guidelines for more.

The tuple case isn’t sound because a tuple is represented as something like this:

#[repr(Rust)] struct Tuple<A, B> { first: A, second: B, }

Because they are #[repr(Rust)] you can’t make any assumptions about layout, including that the 0’th element in the tuple will be first in memory. See Tuple Types in the unsafe code guidelines for more.

If you want to return a tuple, you would need something like this:

fn split<T, const LEN: usize, const INDEX: usize>( array: [T; LEN], ) -> ([T; INDEX], [T; LEN – INDEX]) { #[repr(packed)] struct Tuple<T, const LEN: usize, const INDEX: usize> where [(); LEN – INDEX]:, { first: [T; INDEX], second: [T; LEN – INDEX], } unsafe { let Tuple { first, second }: Tuple<T, LEN, INDEX> = std::mem::transmute(array); (first, second) } }

(playground)

That was actually my first attempt, but it’s not great because a) you need to carry the T and LEN generic parameters around so using turbofish for the INDEX parameter gets a bit awkward (e.g. split::<_, _, 4>([0_u8; 8])), and b) it doesn’t compile because generic_const_exprs is incomplete and the compiler thinks the array and Tuple<T, LEN, INDEX> types have different sizes (“dependently-sized types” is the bit to look out for).

warning: the feature `generic_const_exprs` is incomplete and may not be safe to use and/or cause compiler crashes -> src/lib.rs:1:12 | 1 | #![feature(generic_const_exprs)] | ^^^^^^^^^^^^^^^^^^^ | = note: `#[warn(incomplete_features)]` on by default = note: see issue #76560 <https://github.com/rust-lang/rust/issues/76560> for more information error[E0512]: cannot transmute between types of different sizes, or dependently-sized types -> src/lib.rs:17:61 | 17 | let Tuple { first, second }: Tuple<T, LEN, INDEX> = std::mem::transmute(array); | ^^^^^^^^^^^^^^^^^^^ | = note: source type: `[T; LEN]` (this type does not have a fixed size) = note: target type: `Tuple<T, LEN, INDEX>` (size can vary because of [T; INDEX])