11 个版本 (5 个重大更新)

0.6.3 2021年3月18日
0.6.1 2020年12月29日
0.4.1 2020年11月12日
0.2.0 2020年6月24日

#566Rust 模式

每月下载量30次

MIT/Apache

86KB
1.5K SLoC

simple_parse

crates.io mio Lines of Code

simple_parse 是一个声明式二进制流解析器,旨在在保持安全性的同时为您的自定义类型生成尽可能高效的解析代码。

特性 描述
快速 生成的解析代码通常比“惯用”的 C 实现更快
无复制 能够返回字节切片中的引用
内置端序支持 使用 endian 注释结构体/字段可以控制数字的解析方式
转换回字节 除了解析任意字节外,simple_parse 还允许将结构体转换回二进制形式

如果 simple_parse 无法描述您的复杂/非标准二进制格式,请参阅 deku

使用方法

以下代码片段来自 examples/struct.rs

use ::simple_parse::{SpRead, SpWrite};

#[derive(SpRead, SpWrite)]
pub struct SomeStruct {
    pub some_field: u8,
    #[sp(endian="big")]
    pub items: Vec<u32>,
}

// Emulate data coming from a socket
let mut srv_sock: &[u8] = &[
    1,                      // some_field
    0,0,0,2,                // items.len()
    0xDE,0xAD,0xBE,0xEF,    // items[0]
    0xBA,0xDC,0x0F,0xFE     // items[1]
];

// Parse incoming bytes into SomeStruct
let mut my_struct = SomeStruct::from_reader(&mut srv_sock)?;

/// Modify the struct
my_struct.items.push(0xFFFFFFFF);

/// Encode our struct back into bytes
let mut cli_sock: Vec<u8> = Vec::new();
my_struct.to_writer(&mut cli_sock)?;
//dst_buf == [1, 0, 0, 0, 3, DE, AD, BE, EF, BA, DC, F, FE, FF, FF, FF, FF]

完整示例请见: examples

项目目标

按照优先级模糊排序,simple_parse 努力提供

  1. 安全性
  2. 性能
  3. 易用性
  4. 适应性

换句话说,simple_parse 将试图生成最高性能的代码,同时决不妥协安全性。

其次,将通过提供适用于大多数情况的默认实现,同时允许 一些 自定义以适应我们无法控制的二进制格式来优先考虑易用性(请参阅 bmp 图像解析 示例)。

高级使用

simple_parse 提供了一些方法来增强生成的解析代码。有关选项的完整列表,请参阅 attributes.rs

验证

可以在解析/写入过程的任何位置插入验证“挂钩”。

例如,BMP图像头必须始终以两个字节开头,这两个字节是 'BM'

#[derive(SpRead, SpWrite)]
struct BmpHeader {
    #[sp(validate = "validate_header")]
    magic: u16,
    size: u32,
    reserved1: u16,
    reserved2: u16,
    pixel_array_offset: u32,
    // ...

(摘自 bmp 示例)

这告诉 simple_parse 在读取时填充 u16 之后,在写入时将结构体作为字节写入之前,直接调用 validate_header(magic: &u16, ctx: &mut SpCtx)

自定义长度(对于TLV风格)

simple_parse 通过简单地在元素之前添加元素数量(count)来提供动态大小类型的默认实现。

例如,包含三个值的 Vec 将转换为

// [count] | [count] * [elements]
[3u32][val1][val2][val3]

在解析不遵循此布局的二进制格式时,您可以在动态大小的字段上使用 count 进行注解。

pub struct File {
    pub content_len: u16,
    pub filename: String, // Use the default prepended count
    #[sp(count="content_len")]
    pub contents: Vec<u8>, // Use an existing field as the count

content_len 字段将用于填充 contents,并且 contents.len() 将在写入时写入该偏移量。

自定义读写

simple_parse 的默认读取和写入实现不适合您的格式时,您可以使用 readerwriter 属性来覆盖它们。

struct BmpHeader {
    comp_bitmask: u32,
    #[sp(
        reader="BmpComp::read, comp_bitmask",
        writer="BmpComp::write",
    )]
    compression_info: BmpComp,
    //...

读取时,这将生成类似

compression_info = BmpComp::read(comp_bitmask: &u32, src: &mut Read, ctx: &mut SpCtx)?;

写入时的代码

written_sz += BmpComp::write(&self.compression_info, ctx: &mut SpCtx, dst: &mut Write)?;

注意:使用 reader 会生成次优解析代码,因为 simple_parse 无法对自定义 reader 对输入字节的影响做出任何假设。

许可证

贡献

除非您明确表示,否则根据Apache-2.0许可证定义的您提交给作品的所有有意贡献,应按上述方式双重许可,不得附加任何其他条款或条件。

依赖项

~2MB
~43K SLoC