6 个版本 (2 个稳定版)
1.1.0 | 2020 年 6 月 5 日 |
---|---|
1.0.0 | 2020 年 3 月 15 日 |
0.3.1 | 2019 年 10 月 7 日 |
0.3.0 | 2019 年 1 月 13 日 |
0.1.0 | 2018 年 12 月 19 日 |
#80 在 #cast
630 每月下载次数
在 10 个 crate 中使用(通过 structview)
6KB
80 行
structview
structview
是一个 Rust 库,可以将对二进制数据的引用转换为对更高层次数据结构的引用,例如结构体、联合体和数组。
实现的方法类似于在 C 中解析二进制数据格式时常用的模式,其中表示原始数据的 char *
直接转换为结构体指针等。这种技术具有简单和高度高效的优势。然而,它也是不安全的,因为通常忽略对齐和整数字节序的问题。 structview
通过为用户提供安全接口来避免这些问题。
此 crate 的预期用途是解析二进制数据格式,特别是当仅对某些字段的值感兴趣时。在这些情况下,structview
可以用于高效地查找感兴趣的字段,而无需对无关字段执行潜在的 byteorder 转换。如果所有字段都需要解析,则直接使用 byteorder
crate 可能更直接。
示例
以下示例演示了将二进制数据切片视为简单结构体的过程
use structview::{u32_le, View};
#[derive(Clone, Copy, View)]
#[repr(C)]
struct Animal {
name: [u8; 4],
number_of_heads: u8,
number_of_legs: u32_le,
}
fn main() -> Result<(), structview::Error> {
let data = [0x43, 0x61, 0x74, 0x00, 0x01, 0x04, 0x00, 0x00, 0x00];
let animal = Animal::view(&data)?;
assert_eq!(animal.name, *b"Cat\x00");
assert_eq!(animal.number_of_heads, 1);
assert_eq!(animal.number_of_legs.to_int(), 4);
Ok(())
}
正如示例所示,structview
通过提供 一个(自动可推导的)特性 View
以及 用于安全查看整数字段的类型,使得重新解释原始数据既安全又方便。
要求
需要 Rust 版本 1.38.0 或更高版本。
View 特性
通过实现 View
特性,一个类型承诺它可以安全地从原始二进制数据转换而来。该特性为实现类型添加了几个视图方法,使它们能够从字节数组中生成这些类型的实例的引用。
pub unsafe trait View: Copy {
fn view(data: &[u8]) -> Result<&Self, structview::Error> { ... }
fn view_slice(data: &[u8]) -> Result<&[Self], Error> { ... }
fn view_boxed_slice(data: Box<[u8]>) -> Result<Box<[Self]>, Error> { ... }
}
所有视图方法都会检查给定数据data
的长度,如果字节数过少,则返回Error::NotEnoughData
。此外,两个切片视图方法要求mem::size_of::<Self>() > 0
,否则会panic。
实现View
是不安全的,因为必须确保
- 每个可能的原始字节数值都构成实现类型的有效数据
- 实现类型是1字节对齐的
- 编译器不会改变实现类型字段(在复合类型的情况下)的顺序
structview
已经为1字节整数类型(i8
和u8
)、View
类型数组以及提供的整数视图(u32_le
和类似)实现了View
。基于这些原始类型,用户可以为自己的结构体和联合体创建视图。
手动实现View
trait是不推荐的。相反,它应该像上面示例中那样自动推导。推导确保了通过强制实现结构体和联合体使用repr(C)
并且只包含View
字段来满足上述安全要求。
整数视图
虽然单字节整数i8
和u8
可以从原始数据安全地转换,但更宽的整数不行:它们的对齐方式与字节的1字节对齐不兼容,并且它们的(应用程序定义的)字节序可能与系统的本地字节序不兼容。
structview
通过将这些更宽的整数类型转换为特殊的整数视图来解决此问题:围绕适当大小的u8
数组的包装器,提供了将原始数据解析为实际整数的方法。
示例中使用的u32_le
类型就是这些整数视图之一。它实际上是对U32<LittleEndian>
的别称,这是一个泛型类型,由byteorder
crate提供的ByteOrder
。以下表格列出了所有提供的整数视图
位宽 | 泛型 | 小端 | 大端 |
---|---|---|---|
16 | I16<BO> |
i16_le |
i16_be |
U16<BO> |
u16_le |
u16_be |
|
32 | I32<BO> |
i32_le |
i32_be |
U32<BO> |
u32_le |
u32_be |
|
64 | I64<BO> |
i64_le |
i64_be |
U64<BO> |
u64_le |
u64_be |
每个整数视图都提供了一个to_int
方法,用于解析并返回相应的整数值。每个整数视图还为其整数类型实现了From
转换trait。
在no_std
上下文中的使用
structview
有一个默认启用的功能std
。要在no_std
上下文中使用该crate,请在Cargo.toml
中禁用默认功能
[dependencies.structview]
version = "1"
default-features = false
如果禁用std
structview::Error
没有实现std::error::Error
View::view_boxed_slice
不可用
许可证
本项目采用 MIT 许可证许可(LICENSE 或 http://opensource.org/licenses/MIT)。
除非你明确表示,否则你提交给 structview 的任何有意贡献,都应按上述方式许可,不附加任何额外条款或条件。
lib.rs
:
为 structview
包的 View
特性提供自定义安全的 derive 实现。
依赖
~1.5MB
~35K SLoC