11 个版本

0.2.0 2021 年 9 月 9 日
0.1.10 2021 年 6 月 22 日

#208 in 解析工具

自定义许可证

28KB
414

Zordon

zordan_image

zordon 提供了简单的零拷贝解析和修改的低级别抽象。它是一个具有 alloc 的 no_std 包。

zordon 类型允许将单个可变 u8 缓冲区视为一系列 u8-u128、i8-i128 或 [u8; _] 值,而无需在原始缓冲区中复制数据。通过在调用类型上实现的方法,设置、获取和向值添加是透明的。

可以使用 [MutView] derive 宏应用于字段使用 zordon 类型的数据结构。允许缓冲区像典型的 Rust 结构一样进行解析和处理。

有关使用示例和文档,请参阅:文档


lib.rs:

Zordon

zordan_image

关于

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 宏 MutViewExample 结构体实现了 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] 是剩余的切片。

设置/获取值

ByteViewMulByteView

为了检索/设置底层值,必须调用val/set特质的相应方法。

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