3 个版本 (破坏性更新)
0.3.0 | 2023 年 1 月 10 日 |
---|---|
0.2.0 | 2021 年 4 月 8 日 |
0.1.0 | 2021 年 1 月 15 日 |
1431 在 解析器实现 中
每月 814 次下载
16KB
161 行
bytes-cast
安全地将 &[u8]
字节重新解释为自定义结构体,不进行复制,以高效地读取结构化二进制数据。
致谢
此软件包包含来自 https://github.com/Lokathor/bytemuck 的代码。
问题陈述
当从磁盘读取给定格式的文件时,“传统”的解析技术,如使用 nom
软件包,通常涉及在内存中创建不同的数据结构,这可能导致分配和复制代价昂贵。
对于适合此方法的二进制格式,在内存中有一个与磁盘上相同的字节缓冲区可能更高效,可能由内核直接内存映射,并且只需按需访问其部分。但完全使用手动索引或指针操作可能会出错。
通过定义内存布局与二进制格式匹配的 struct
,然后将指针转换为操作引用、数组或这些结构体的切片,我们可以让编译器执行大多数偏移量计算,并拥有更易读的代码。
问题和检查
-
一些 Rust 类型具有有效性约束,并且不能从任意字节进行转换。例如,创建一个内存中值为非
0_u8
或1_u8
的bool
是未定义行为。类似地,对于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