将Vec <u8>转换为Vec <[u8; N]>

时间:2020-08-18 08:50:32

标签: rust

我有Vec<u8>想要转换为(新类型)数组的(新类型)Vec。我想不出我为什么不能重用现有分配的原因,所以这就是我想出的:

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);
}

这是执行此操作的正确方法吗?有安全方法可以做到这一点吗?

0 个答案:

没有答案