#byte #packed #endian #transmute #binary #no-alloc

无std packbytes-derive

packbytes crate的派生宏

1个不稳定版本

0.1.0 2024年2月15日

#30#transmute


2 个crate中使用(通过 packbytes

MIT 许可证

21KB
400

crates.io | 文档

将结构体转换为和从固定大小的堆栈上的字节数组表示形式。

您可以使用它们从 std::io::Reader 中读取结构体或将它们写入 std::io::Writer,只需一个 readwrite 调用即可。

动机

当将结构化数据读入Rust结构体(如文件的头信息)时,人们可能会想简单地这样做

use std::io;

struct MyStruct {
    version: u8,
    kind: u16,
    matrix: [i32; 16]
}

// Do not do this
fn read_my_struct<R: io::Read>(reader: &mut R) -> io::Result<MyStruct> {
    let mut bytes = [0; std::mem::size_of::<MyStruct>()];
    reader.read_exact(&mut bytes)?;
    Ok(unsafe { std::mem::transmute(bytes) })
}

使用 unsafe 是不行的!Rust结构体的内存对齐通常在字段之后包含一些填充,而文件中的数据是紧密打包的,一个接一个。因此,只有在结构体是 repr(packed) 时才安全,这不仅对性能不利,还可能导致某些平台上的未定义行为。此外,数据的 字节序 必须与平台的字节序相匹配。

此crate允许通过将结构体转换为和从打包的字节表示形式来安全地进行前面的操作(不使用 unsafe),这是通过 ToBytesFromBytes 特性来完成的,这些特性可以自动派生到大多数结构体中。比较

use std::io;
use packbytes::{FromBytes, ByteArray};

#[derive(FromBytes)]
struct MyStruct {
    version: u8,
    kind: u16,
    matrix: [i32; 16]
}

fn read_my_struct<R: io::Read>(reader: &mut R) -> io::Result<MyStruct> {
    let mut bytes = [0; <MyStruct as FromBytes>::Bytes::SIZE];
    reader.read_exact(&mut bytes)?;
    Ok(MyStruct::from_bytes(bytes))
}

可以将 from_bytesto_bytes 方法视为将结构体从其本机内存表示形式解包和打包。

为了方便,提供了 read_packedwrite_packed 方法来读取和写入。

当不是每个字节序列都表示有效数据时(例如,当字段只能获得一组很小的值时),可以使用特性 TryFromBytes

字节序

默认情况下,FromBytesToBytes 继承宏假定数据应该以小端序存储,这也是 from_bytesto_bytes 方法所使用的。您可以通过设置属性 #[packbytes(be)] 以大端序或 #[packbytes(ne)] 以平台本地字节序来更改这一点。

no_std 支持

除了便捷方法外,这个 crate 中的所有内容都不需要 std。可以关闭 std 功能。实际上,由于所有操作都在堆栈上执行,甚至不需要 alloc


lib.rs:

packbytes crate 的继承宏。

依赖项

~275–730KB
~17K SLoC