data must be valid for reads for len * mem::size_of::<T>() many bytes, and it must be properly aligned. This means in particular:
The entire memory range of this slice must be contained within a single allocated object! Slices can never span across multiple allocated objects. See below for an example incorrectly not taking this into account.
I believe ArrayWithHeaderHack does match the documentation conditions, but unsafe Rust is not a trivial thing, so I have to ask here.
Also, out of curiosity, is #[repr(C)] necessary here?
Seems sound to me. The only thing I would change is not to use transmute. You can simply cast the pointer. self as *const ArrayWithHeaderHack<T, N> as *const T. Or somewhat shorter self as *const _ as *const T.
Note that the term “allocated object” might be confusing you. All fields of a struct will always be part of the same allocation, be it a stack allocation or a heap allocation, so the condition is not violated.
Absolutely. Most #[repr(Rust)] types provide no guarantees on layout by default.
Other than that, this looks OK to me. The reference is pointing to the entirety of self (IIUC type punning only self.headerwould be unsound due to the entire-allocation precondition). The alignment of [T; N] is the same as that of T, and the size of [T; N] is guaranteed to be size_of::<T>() * N, so these together mean no padding and a correct alignment/size for the struct, overall.
I second @steffahn about not transmuting pointers; that's something that you should basically never do, because it's not what you intended (you are trying to transmute the pointed value, not the pointer, and soundness of transmuting is not transitive w.r.t. indirection).