Here is an example of how to transmute a Sized
type from a raw pointer:
use std::mem;
#[derive(Eq, PartialEq)]
#[repr(packed)]
struct Bob {
id: u32,
age: u32,
}
unsafe fn get_type<'a, T: Sized>(p: *const u8) -> &'a T {
mem::transmute(p)
}
#[test]
fn it_works() {
let bob = Bob {
id: 22,
age: 445,
};
let bob2: &Bob = unsafe {
let ptr: *const u8 = mem::transmute(&bob);
get_type(ptr)
};
assert_eq!(&bob, bob2);
}
However, for my application I want to be able to get a ?Sized
type instead of a Sized
type. However, this doesn't work:
unsafe fn get_type2<'a, T: ?Sized>(p: *const u8) -> &'a T {
mem::transmute(p)
}
It fails with this error message:
error: transmute called with differently sized types: *const u8 (64 bits) to &'a T (pointer to T) [--explain E0512]
--> src/main.rs:2:9
|>
2 |> mem::transmute(p)
|> ^^^^^^^^^^^^^^
I have tried to give it a &[u8]
(fat pointer) by converting it using std::slice::from_raw_parts
, but it fails with pretty much the same error message.
You actually cannot for the very reason cited in the error message.
Rust references can be either pointer-sized (for Sized
types) or bigger (for !Sized
types). For example, if Trait
is a trait, a &Trait
reference is actually two fields as defined by std::raw::TraitObject
.
So, in order to form a reference to an unsized type, you have to:
std::raw::TraitObject
, std::raw::Slice
, ...)and then you have to fill in the blanks (there is more than just a pointer).
So, unless you can limit your function to producing &T where T: Sized
, you cannot just transmute a raw pointer to &T
.