I'm serializing a slice of integers like this:
fn serialize(value: &[i32]) -> &[u8] {
let size = value.len() * 4;
unsafe {
slice::from_raw_parts(value as *const [i32] as *const u8, size)
}
}
Apart from the multiplication with 4, it should be zero-cost.
Now the bytes get transferred or stored and reloaded from somewhere, and I have an unaligned slice of u8
's that I want to deserialize. I can't use the same trick because the slice of bytes might be misaligned in memory.
Thus, I came up with the following function:
fn deserialize(bytes: &[u8]) -> Vec<i32> {
let len = bytes.len() / 4;
unsafe {
let chunks: &[[u8; 4]] = slice::from_raw_parts(
bytes as *const [u8] as *const [u8; 4],
len,
);
let mut vec: Vec<i32> = Vec::with_capacity(len);
for i in 0..len {
vec.push(transmute_copy::<[u8; 4], i32>(&chunks[i]));
}
vec
}
}
But this feels overly complex and non-efficient. Is there any better way to achieve this re-alignment?
Example below:
use std::mem::transmute_copy;
use std::slice;
fn serialize(value: &[i32]) -> &[u8] {
/* … */
}
fn deserialize(bytes: &[u8]) -> Vec<i32> {
/* … */
}
fn main() {
let vec = vec![15, 11, -2, 300];
println!("vec = {vec:?}");
let bytes = serialize(&vec);
println!("bytes = {bytes:?}");
let copied_bytes = Vec::from(bytes);
let restored = deserialize(&copied_bytes);
println!("restored = {restored:?}");
}
Output:
vec = [15, 11, -2, 300]
bytes = [15, 0, 0, 0, 11, 0, 0, 0, 254, 255, 255, 255, 44, 1, 0, 0]
restored = [15, 11, -2, 300]