#binary-data #byte-slice #structs #binary-format #pointers #reading #structured

bytes-cast

安全地将 &[u8] 字节重新解释为自定义结构体,不进行复制,以高效地读取结构化二进制数据

3 个版本 (破坏性更新)

0.3.0 2023 年 1 月 10 日
0.2.0 2021 年 4 月 8 日
0.1.0 2021 年 1 月 15 日

1431解析器实现

Download history 275/week @ 2024-03-13 414/week @ 2024-03-20 450/week @ 2024-03-27 303/week @ 2024-04-03 357/week @ 2024-04-10 161/week @ 2024-04-17 282/week @ 2024-04-24 297/week @ 2024-05-01 220/week @ 2024-05-08 272/week @ 2024-05-15 164/week @ 2024-05-22 161/week @ 2024-05-29 178/week @ 2024-06-05 280/week @ 2024-06-12 194/week @ 2024-06-19 145/week @ 2024-06-26

每月 814 次下载

Zlib OR Apache-2.0 OR MIT

16KB
161

bytes-cast

安全地将 &[u8] 字节重新解释为自定义结构体,不进行复制,以高效地读取结构化二进制数据。

crates.io docs.rs

致谢

此软件包包含来自 https://github.com/Lokathor/bytemuck 的代码。

问题陈述

当从磁盘读取给定格式的文件时,“传统”的解析技术,如使用 nom 软件包,通常涉及在内存中创建不同的数据结构,这可能导致分配和复制代价昂贵。

对于适合此方法的二进制格式,在内存中有一个与磁盘上相同的字节缓冲区可能更高效,可能由内核直接内存映射,并且只需按需访问其部分。但完全使用手动索引或指针操作可能会出错。

通过定义内存布局与二进制格式匹配的 struct,然后将指针转换为操作引用、数组或这些结构体的切片,我们可以让编译器执行大多数偏移量计算,并拥有更易读的代码。

问题和检查

  • 一些 Rust 类型具有有效性约束,并且不能从任意字节进行转换。例如,创建一个内存中值为非 0_u81_u8bool 是未定义行为。类似地,对于 enum 也是如此。

  • 当类型的 align_of 大于一时,在不是对齐倍数的地址访问该类型的值是未定义行为。对齐还可以导致结构体具有填充,使得字段偏移量不是我们所期望的。相反,我们可以创建辅助类型,例如包装 [u8; 4] 并将其转换为 u32

  • 用于存储或传输的二进制格式通常强制要求使用小端或大端。辅助类型还可以处理从 CPU 的本地端序到端序的转换。

  • 默认情况下,Rust编译器可以选择重新排列结构体字段(以减少填充)。这又可能导致字段偏移量不是我们所期望的。可以通过给结构体添加#[repr(C)]#[repr(transparent)]来禁用此功能。

此crate在编译时结合了Rust对所有上述内容的检查。有关API详情,请参阅文档

为什么还需要另一个crate

bytemuck和其他一些项目已经存在,具有非常相似的目标。这个crate在某种程度上做出了不同的设计选择,并且有一些主观意见。

  • 它只转换从&[u8]字节数据,并不试图更通用或适应更多用例。

  • 提供比必要的更多字节数不是错误。相反,切片的开始被重新解释,剩余的字节成为返回值的一部分,以便进一步处理。(如果需要精确长度,调用者可以检查或断言remaining.is_empty())。

  • 它在编译时强制要求align_of() == 1,而不是在运行时检查指针对齐,从而消除了一个需要处理的中断或错误类别。只有不足的字节是错误情况。具有align_of() == 1的字段也消除了结构体中的任何填充。

依赖项

~1.5MB
~35K SLoC