11 个版本
0.2.0 | 2021 年 9 月 9 日 |
---|---|
0.1.10 | 2021 年 6 月 22 日 |
#208 in 解析工具
28KB
414 行
Zordon
zordon
提供了简单的零拷贝解析和修改的低级别抽象。它是一个具有 alloc 的 no_std 包。
zordon
类型允许将单个可变 u8 缓冲区视为一系列 u8-u128、i8-i128 或 [u8; _] 值,而无需在原始缓冲区中复制数据。通过在调用类型上实现的方法,设置、获取和向值添加是透明的。
可以使用 [MutView]
derive 宏应用于字段使用 zordon
类型的数据结构。允许缓冲区像典型的 Rust 结构一样进行解析和处理。
有关使用示例和文档,请参阅:文档
lib.rs
:
Zordon
关于
zordon
提供了简单的零拷贝解析和修改的低级别抽象。它是一个具有 alloc 的 no_std 包。
zordon
类型允许将单个可变 u8 缓冲区视为一系列 u8-u128、i8-i128 或 [u8; _] 值,而无需在原始缓冲区中复制数据。通过在调用类型上实现的方法,设置、获取和向值添加是透明的。
可以使用 [MutView]
derive 宏应用于字段使用 zordon 类型的数据结构。允许缓冲区像典型的 Rust 结构一样进行解析和处理。
简单示例
use zordon::prelude::*;
#[derive(MutView)]
struct Example<'a> {
u8_f: ByteView<'a, u8>,
u16_f: MulByteView<'a, u16, BigEnd>,
arr_f: ArrayView<'a, [u8; 3]>,
}
fn main() {
let mut input_buf = [0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07];
let (mut example, _) = Example::mut_view(&mut input_buf);
assert_eq!(example.u8_f.val(), 0x00);
assert_eq!(example.u16_f.val(), 0x0102);
assert_eq!(*example.arr_f.as_ref(), [0x03, 0x04, 0x05]);
}
它是如何工作的
派生 mut_view
#[derive(MutView)]
struct Example<'a> {
u8_f: ByteView<'a, u8>,
u16_f: MulByteView<'a, u16, BigEnd>,
arr_f: ArrayView<'a, [u8; 3]>,
}
derive 宏 MutView
为 Example
结构体实现了 mut_view
方法。
ByteView<'a, u8>
指定底层数据是单个字节的类型 [u8
]MulByteView<'a, u16, LitEnd>
指定底层数据是类型 [u16
] 的小端两个字值。LitEnd
可以与BigEnd
交换,数据将被视为大端。u16
可以与 u32-u128 或 i16-i128 交换
ArrayView<'a, [u8; 3]>
指定底层数据是类型为 [u8; 3
] 的三个字节值。
实例化结构体
let mut input_buf = [0x00, 0x01, 0x02, 0x03, 0x04, 0x05];
let (mut example, _) = Example::mut_view(&mut input_buf);
mut_view
使用一个&mut [u8]
作为输入,根据字段类型将其切割成不同长度的多个可变切片。每个切片的所有权都转移给了相应的字段。
在这种情况下,它会这样做:
- 首先,在索引1处拆分
input_buf
(因为 [u8
] 的长度为1) -u8_f
现在拥有这个切片 - 其次,在索引2处拆分剩余的切片(因为 [
u16
] 的长度为两个) -u16_f
现在拥有这个切片 - 最后,它会在索引3处拆分剩余的切片(因为 [
u8; 3
] 的长度为三个) -arr_f
现在拥有这个切片
mut_view
的返回值是 (Self, &'mut [u8]),其中 Self
是调用类型,&'mut [u8]
是剩余的切片。
设置/获取值
ByteView
和 MulByteView
为了检索/设置底层值,必须调用val/set特质的相应方法。
- 对于
ByteView
,必须引入ModByteView
特质。 - 对于
MulByteView
,必须引入ModMulByteView
特质
use zordon::prelude::*;
#[derive(MutView)]
struct Example<'a> {
u8_f: ByteView<'a, u8>,
}
fn main() {
let mut input_buf = [0x00];
let (mut example, _) = Example::mut_view(&mut input_buf);
assert_eq!(example.u8_f.val(), 0x00);
example.u8_f.set(0xFF);
assert_eq!(input_buf[0], 0xFF);
}
ArrayView
检索 ArrayView
的底层值的方式略有不同。它返回的是数据的可变/不可变引用,而不是数据本身。
#[derive(MutView)]
struct Example<'a> {
arr_f: ArrayView<'a, [u8; 3]>,
}
fn main() {
let buf = [0x00, 0x01, 0x02];
let mut input_buf = buf.clone();
let (mut example, _) = Example::mut_view(&mut input_buf);
// as reference
assert_eq!(*example.arr_f.as_ref(), buf.clone());
// set
example.arr_f.set(&[0xAA, 0xBB, 0xCC]);
assert_eq!(*example.arr_f.as_ref(), [0xAA, 0xBB, 0xCC]);
// as mutable reference
{
let mut m_ref = example.arr_f.as_mut_ref();
m_ref[0] = 0xFF;
}
assert_eq!(input_buf, [0xFF, 0xBB, 0xCC]);
}
复合示例
use zordon::prelude::*;
#[derive(MutView)]
struct ExampleA<'a> {
u8_f: ByteView<'a, u8>,
}
#[derive(MutView)]
struct ExampleB<'a> {
u16_f: MulByteView<'a, u16, BigEnd>,
}
#[derive(MutView)]
struct Composite<'a> {
example_a: ExampleA<'a>,
example_b: ExampleB<'a>,
option_c: Option<u8>,
}
fn main() {
let mut input_buf = [0x00, 0x01, 0x02, 0x03, 0x04, 0x05];
let (mut comp_e, _) = Composite::mut_view(&mut input_buf);
assert_eq!(comp_e.example_a.u8_f.val(), 0x00);
assert_eq!(comp_e.example_b.u16_f.val(), 0x0102);
assert_eq!(comp_e.option_c, None);
comp_e.example_a.u8_f.set(0xFF);
assert_eq!(input_buf[0], 0xFF);
}
VarArrayView
示例
此类型创建了一个可变数组视图,其长度在编译时未知。
use zordon::prelude::*;
fn main() {
let arr = &mut [0x1 as u8, 0x2, 0x3, 0x4] as &mut [u8];
let buf = arr.iter().map(|x| x.clone()).collect::<Vec<u8>>();
let (t, _): (VarArrayView<u8>, _) = VarArrayView::mut_view(arr, arr.len());
assert_eq!(*t.as_ref(), buf);
}
更多示例
(尚未发布)的crate使用zordon进行零拷贝解析PE格式。
特性
- 零拷贝 – 原始缓冲区被分割成可变切片
- 能够解析以下类型:
[u8, u16, u32, u64, u128, i8, i16, i32, i64, i128, [u8; _], &mut [u8]]
- 类型u16..u128和i16..i128可以被处理为小端或大端格式。
- 通过
MutView
派生宏,为结构体自动实现mut_view
。
依赖项
~1.5MB
~37K SLoC