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 日 |
#805 在 解析器实现
每月 617 次下载
在 9 个 crate 中使用 (通过 twmap)
18KB
129 行
structview
structview
是一个 Rust 库,用于将二进制数据的引用转换为更高层次的数据结构的引用,例如结构体、联合体和数组。
实现的方法类似于在 C 中解析二进制数据格式时常用的模式,其中表示原始数据的 char *
直接转换为结构体指针等。这种技术具有简单和高效的优势。不幸的是,它也是不安全的,因为通常会忽略对齐和整数字节序的问题。 structview
通过为用户提供安全的接口来避免这些问题。
此 crate 的预期用例是解析二进制数据格式,尤其是如果只对某些字段的值感兴趣,而不是所有字段。在这些情况下,structview
可以用来高效地找到感兴趣的字段,而无需对无关的字段进行潜在的字节序转换。如果所有字段都需要解析,则直接使用 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
通过提供 一个可自动派生的 trait View
以及 用于安全查看整数字段的类型,使得重新解释原始数据既安全又方便。
要求
需要 Rust 版本 1.38.0 或更高版本。
View
Trait
通过实现 View
trait,类型保证可以从原始二进制数据安全地转换为。该 trait 为实现类型添加了几个视图方法,使得可以从字节切片生成这些类型的实例的引用。
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
,否则会引发恐慌。
实现 View
是不安全的,因为必须确保
- 每个可能的原始字节数值都构成实现类型的有效数据
- 实现类型是 1 字节对齐的
- 编译器不会改变实现类型字段的顺序(在复合类型的情况下)
structview
已经为 1 字节整数类型(i8 和
u8
)、View
类型数组以及提供的整数视图(u32_le 和朋友)实现了
View
。基于这些原语,用户可以为自己的结构体和联合体创建视图。
不建议手动实现 View
特性。相反,应该像上面的示例那样自动推导。推导确保了安全性,强制实施实现结构体和联合体是 repr(C)
并且只包含 View
字段。这足以满足上述安全性要求。
整数视图
虽然单字节整数 i8
和 u8
可以安全地从原始数据转换,但更宽的整数则不行:它们的对齐方式与字节数组的 1 字节对齐不兼容,并且它们的(应用程序定义的)字节序可能与系统的本地字节序不兼容。
structview
通过将这些更宽的整数类型转换成特殊的整数视图来解决此问题:这些视图是适当大小的 u8
数组的包装,提供将原始数据解析为实际整数的方法。
示例中使用的 u32_le
类型就是这些整数视图之一。实际上,它是 U32<LittleEndian>
的别名,这是一个由 byteorder
包 提供的泛型类型 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
转换特性。
在 no_std
上下文中的使用
structview
有一个特性,std
,默认启用。要在 no_std
上下文中使用该包,请在 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 的任何贡献,都应按照上述许可证授权,不附加任何额外条款或条件。
依赖项
约 1.5MB
约 37K SLoC