Reputation: 2244
I am using packed structs and I need to be able to go from raw bytes to structs and vice versa without any decoding/encoding overhead.
I wrote some code that seemed to work:
#[packed]
struct Test {
data: u64
}
impl Test {
fn from_byte_slice(bs: &[u8]) -> Option<Test> {
if bs.len() != std::mem::size_of::<Test>() {
None
} else {
let p: *const u8 = &bs[0];
let p2: *const Test = p as *const Test;
unsafe {
Some(*p2)
}
}
}
}
However I have a couple of different structs that need to be serialized/deserialed so I wanted to use a generic function to reduce code duplication.
The following code fails to compile with the error message: "error: cannot move out of dereference of *
-pointer"
fn from_byte_slice<T>(bs: &[u8]) -> Option<T> {
if bs.len() != std::mem::size_of::<T>() {
None
} else {
let p: *const u8 = &bs[0];
let p2: *const T = p as *const T;
unsafe {
Some(*p2)
}
}
}
What is weird is that if I instead of returning an Option return an Option<&T> then the code compiles:
fn from_byte_slice<'a, T>(bs: &'a [u8]) -> Option<&'a T> {
if bs.len() != std::mem::size_of::<T>() {
None
} else {
let p: *const u8 = &bs[0];
let p2: *const T = p as *const T;
unsafe {
Some(&*p2)
}
}
}
Am I doing something wrong or have I run into a bug in the borrow checker?
Upvotes: 0
Views: 393
Reputation: 16198
The argument bs: &[u8]
is a slice, and is borrowed. This is a form of temporary ownership, you can't move the data out. *p2
does just that, it moves ownership of that data out.
You need to clone it:
fn from_byte_slice<T: Clone>(bs: &[u8]) -> Option<T> {
if bs.len() != std::mem::size_of::<T>() {
None
} else {
let p: *const u8 = &bs[0];
let p2: *const T = p as *const T;
unsafe {
Some((*p2).clone())
}
}
}
Using transmute
you probably can make this work with a Vec<u8>
instead, if you don't mind moving an owned vector into the function.
The direct impl in the first case works because Test
contains all Copy
fields and is thus implicitly copied (instead of needing the explicit clone()
).
This probably will change soon, Copy
will have to be explicitly derived in the future.
Upvotes: 3