I have Vec<u8>
which I want to convert to (newtyped) Vec
of (newtyped) arrays. I couldn't think of reason why I couldn't reuse existing allocation, so this is what I came up with:
use std::mem::{size_of, transmute, ManuallyDrop};
// If I understand correctly, size_of::<u8; N>() == N and
// repr(transparent) ensures that for newtyped [u8; N] too.
#[derive(Debug)]
#[repr(transparent)]
struct Foo([u8; 4]);
#[derive(Debug)]
struct FooVec(Vec<Foo>);
impl From<Vec<u8>> for FooVec {
fn from(vec: Vec<u8>) -> Self {
// Prevent contents of vec being dropped.
let mut vec = ManuallyDrop::new(vec);
// Compute length of foovec and ensure that there aren't any leftover bytes.
let len = vec.len();
assert!(len % size_of::<Foo>() == 0);
let len = len / size_of::<Foo>();
// Compute capacity of foovec and ensure that there aren't any leftover allocated bytes.
let cap = if vec.capacity() % size_of::<Foo>() == 0 {
vec.capacity() / size_of::<Foo>()
} else {
let cap = vec.capacity();
let size = size_of::<Foo>();
vec.reserve_exact(size - (cap % size));
vec.capacity() / size
};
// Get pointer to contents of vec and transmute it to desired type.
let ptr = unsafe { transmute::<*mut u8, *mut Foo>(vec.as_mut_ptr()) };
// Construct foovec.
unsafe { FooVec(Vec::from_raw_parts(ptr, len, cap)) }
}
}
// Prints:
// [0, 1, 2, 3, 4, 5, 6, 7]
// FooVec([Foo([0, 1, 2, 3]), Foo([4, 5, 6, 7])])
fn main() {
let vec: Vec<u8> = vec![0, 1, 2, 3, 4, 5, 6, 7];
println!("{:?}", vec);
let foovec = FooVec::from(vec);
println!("{:?}", foovec);
}
Is this correct way to do this. Is there a safe way to do this?