将u8缓冲区转换为Rust中的struct

sud*_*udo 6 rust data-structures

我有一个未知大小的字节缓冲区,我想创建一个指向缓冲区开头内存的本地struct变量.按照我在C中所做的,我在Rust中尝试了很多不同的东西并且不断出错.这是我最近的尝试:

use std::mem::{transmute, size_of};

#[repr(C, packed)]
struct my_struct {
    foo: u16,
    bar: u8,
}

fn main() {
    let v: Vec<u8> = vec![1, 2, 3];
    let buffer = v.as_slice();
    let s: my_struct = unsafe { transmute(buffer[..size_of::<my_struct>()]) };
}
Run Code Online (Sandbox Code Playgroud)

我收到以下消息的错误:

  • 特质std::marker::Sized没有实现[u8]
  • 注意:[u8]在编译时没有已知的常量
  • 注意:要求 std::mem::transmute

Mat*_* M. 9

您可以使用std::ptr::readstd::ptr::write直接读取/写入对象(还有其他std::ptr值得检查的方法).

在您的情况下,这很简单:

fn main() {
    let v: Vec<u8> = vec![1, 2, 3];
    let s: MyStruct = unsafe { std::ptr::read(v.as_ptr() as *const _) };
    println!("here is the struct: {:?}", s);
}
Run Code Online (Sandbox Code Playgroud)

我个人会鼓励您在可重用的方法中包装它,并在尝试读取之前对源缓冲区执行长度检查.


She*_*ter 7

如果您不想将数据复制到结构中而是将其保留在原处,则可以使用slice::align_to. 这将创建一个&MyStruct

#[repr(C, packed)]
#[derive(Debug, Copy, Clone)]
struct MyStruct {
    foo: u16,
    bar: u8,
}

fn main() {
    let v = vec![1u8, 2, 3];

    // I copied this code from Stack Overflow
    // without understanding why this case is safe.
    let (head, body, _tail) = unsafe { v.align_to::<MyStruct>() };
    assert!(head.is_empty(), "Data was not aligned");
    let my_struct = &body[0];

    println!("{:?}", my_struct);
}
Run Code Online (Sandbox Code Playgroud)

在这里,align_to将一些字节转换为MyStruct是安全的,因为我们已经使用过repr(C, packed)并且所有类型都MyStruct可以是任意字节。

也可以看看: