如何将 `Vec<u8>` 转换为不同的结构,并删除 Vec,同时拥有其他结构的所有权

问题描述 投票:0回答:2

我有一个从磁盘读取

Vec<u8>
的函数,我想将其解释为 ext2 超级块(这是一个打包结构)。

所以我用了:

unsafe {&*(raw_super.as_ptr() as *const Super block)}

问题是当函数返回时

Vec
被丢弃,所以超级块只有0s

我想要一种将 Vec 转换为超级块并拥有超级块中的数据的方法,如果可能的话,需要小的成本抽象

rust unsafe
2个回答
0
投票

正如其他人之前在评论中指出的那样,您必须首先断言几个先决条件:

  • 字节序正确(ext2 使用小字节序
  • u8
    SuperBlock
    的对齐方式是相同的(但是
    u8
    #[repr(packed)]
    结构总是满足
    packed
    隐式地
    packed(1)
  • Vec<u8>
    (它是
    len()
    )的大小与
    SuperBlock
  • 的大小相同
  • 结构体中字段的顺序是已知的,并且与指定的相同
    ext2

因此您可以将

Vec<u8>
转换为
Box<SuperBlock>
,如下所示:

// `C` so the order of the fields in memory is known
// `packed` so the alignment is 1 and there is no padding
#[repr(C, packed)]
pub struct SuperBlock {
    foo: u16,
    bar: u32,
}

// ext2 superblocks are always little endian, so this works only for those platforms
#[cfg(target_endian = "little")]
impl SuperBlock {
    /// ## Errors
    /// Returns the vector unchanged when it's length isn't exactly the size of a `SuperBlock`
    pub fn from_vec(v: Vec<u8>) -> Result<Box<Self>, Vec<u8>> {
        if v.len() != std::mem::size_of::<SuperBlock>() {
            return Err(v);
        }
        // SAFETY:
        // `#[repr(packed)] structs have an alignment of 1, the same as u8
        // v.len() and size_of::<SuperBlock>() are the same as asserted above
        Ok(unsafe { Box::from_raw(Box::into_raw(v.into_boxed_slice()).cast::<SuperBlock>()) })
    }
}

游乐场

从技术上讲,这不会drop

Vec
,而是为返回的
Box<SuperBlock>

重用相同的分配

0
投票

您可以使用出色的

bytemuck
板条箱将
Vec<u8>
中的数据安全地转换为
SuperBlock
。例如:

use bytemuck::{Pod, Zeroable};

#[derive(Copy, Clone, Pod, Zeroable)]
#[repr(C, packed)]
pub struct SuperBlock {
    foo: u16,
    bar: u32,
}

pub struct OwnedSuperBlock {
    data: Vec<u8>,
}

impl OwnedSuperBlock {
    pub fn new(data: Vec<u8>) -> Self {
        OwnedSuperBlock { data }
    }

    pub fn as_super_block(&self) -> &SuperBlock {
        bytemuck::from_bytes(&self.data)
    }
}

游乐场

由于

bytemuck::Pod
特征和派生宏提供的保证,此代码不使用不安全。它们确保将向量中的字节转换为
&SuperBlock
是安全的,同时还检查字节大小是否正确。最后,整个事情是零复制的,并且涉及最小的运行时成本(仅是数据大小检查)。

© www.soinside.com 2019 - 2024. All rights reserved.