When I try to compile this method, the compiler reports that mem::transmute is being called on types of different sizes. (Which doesn't make sense because T size should be known in this context).
pub fn partition2<T: Sized>(source: [T; 52]) -> [[T; 13]; 4] {
use std::mem;
unsafe { mem::transmute(source) }
}
error[E0512]: transmute called with types of different sizes
--> src/main.rs:9:14
|
9 | unsafe { mem::transmute(source) }
| ^^^^^^^^^^^^^^
|
= note: source type: [T; 52] (size can vary because of T)
= note: target type: [[T; 13]; 4] (size can vary because of T)
Replacing T with a struct and it compiles fine (also works with String):
pub struct Card {
value: u8,
suit: Suit
}
pub enum Suit {
Spades,
Clubs,
Diamonds,
Hearts,
}
pub fn partition(source: [Card; 52]) -> [[Card; 13]; 4] {
use std::mem;
unsafe { mem::transmute(source) }
}
rustc 1.24.0-nightly (23032d0af 2017-11-30)
binary: rustc
commit-hash: 23032d0afa2b0e0c60a9b2ae62709f846d90007c
commit-date: 2017-11-30
host: x86_64-apple-darwin
release: 1.24.0-nightly
LLVM version: 4.0
I doubt if we can easily fix this without pushing this E0512 error to post-monomorphization. Allowing this means the compiler has to be able to solve equations to prove that size_of::<T>() * 52 == (size_of::<T>() * 13) * 4.
size_of::<T>() doesn鈥檛 really matter though right? Whatever it is post-monomorphization, it鈥檚 the same on both sides.
The check for equal size is pre-monomorphization (intentionally). So the compiler would have to reason about the size of the type parameter T abstractly to some degree.
I think having a compiler able to solve first degree equations like that is going to be useful once we have const generics.
I believe the correct answer here is "just use pointer casting". I don't think there's a good argument for adding complexity here when the method's use is discouraged anyway.
I'm confident, however, that eventually we'll have const bounds enough to allow things like where const size_of::<T>() == size_of::<U>(), but that's a long way off -- the current RFC doesn't even know that N+1 == N+1, having intentionally left all such equation solving for a future RFC: https://github.com/rust-lang/rfcs/blob/master/text/2000-const-generics.md#equality-of-two-abstract-const-expressions
Triage: two years later, I think we should close this. Maybe it can be done someday, as @scottmcm points out, but it's unclear when that, if ever, will happen.
It would be useful to have a working example of the "just use pointer casting" technique in the interim while waiting for something to be implemented.
I'm arriving at this thread after writing a function which attempts to transmute a [MaybeUninit<T>; const_size]. transmute is the recommended method when initializing that type, and it's unclear how to accomplish this when generics are involved.
There is a crate which allows for this call to be made - transmute
An an update to anyone following this, there's a group working on safe transmutes that may end up being the solution for this desire: https://github.com/rust-lang/lang-team/issues/21
Most helpful comment
The check for equal size is pre-monomorphization (intentionally). So the compiler would have to reason about the size of the type parameter
Tabstractly to some degree.