9个不稳定版本 (3个重大变更)
0.6.3 | 2021年3月18日 |
---|---|
0.6.2 | 2021年3月5日 |
0.6.1 | 2020年12月29日 |
0.5.0 | 2020年12月22日 |
0.1.0 | 2020年6月23日 |
#77 in #endian
每月下载量38次
在 simple_parse 中使用
60KB
1K SLoC
simple_parse
simple_parse
是一个声明式二进制流解析器,旨在为您的自定义类型生成尽可能高效的解析代码,同时保持安全性。
功能 | 描述 |
---|---|
单次“复制” | 尽可能将数据直接读取到其最终目的地 |
内置端序支持 | 使用 endian 注释结构体/字段可以控制数字的解析方式 |
转换回字节 | 除了解析任意字节外,simple_parse 还允许将结构体以二进制形式回溯 |
如果 simple_parse
无法描述您的复杂/非标准二进制格式,请查看 deku 或 binrw。
使用方法
查看 client_server 以获取完整示例。
use ::simple_parse::{SpRead, SpWrite};
#[derive(SpRead, SpWrite)]
pub enum Message {
Ping,
Pong,
Chat(String),
Key {
private: Vec<u8>,
public: Vec<u8>,
},
Disconnect,
}
pub fn main() {
/* <...> */
// Declare a destination buffer to use when parsing
let mut dst: MaybeUninit<Message> = MaybeUninit::uninit();
loop {
// Receive & parse bytes from the socket as a `Message` using SpRead
let msg = Message::from_reader(&mut sock, &mut dst).expect("[server] Failed to receive message");
match msg {
Message::Ping => {
println!("[server] Got Ping ! Sending Pong...");
// Respond with a Pong using SpWrite
(Message::Pong).to_writer(&mut sock).expect("[server] Failed to send Pong");
},
Message::Pong => println!("[server] got pong !"),
Message::Chat(s) => println!("[server] Received chat : '{s}'"),
Message::Key{private, public} => println!("[server] got keys : {private:X?}:{public:X?}"),
Message::Disconnect => break,
}
}
/* <...> */
}
更多示例请参阅: examples/
项目目标
按照优先级大致顺序,simple_parse
旨在提供
- 安全性
- 性能
- 易用性
- 适应性
换句话说,simple_parse
将尝试生成最高效的代码,同时从不妥协安全性。
其次,将通过提供适用于大多数情况的默认实现来优先考虑易用性,同时允许对无法控制的二进制格式进行一些自定义。
高级用法
simple_parse
提供了几种增强生成解析代码的方法。请参阅 attributes.rs 以获取选项的完整列表。
验证
可以在解析/写入过程的任何位置插入验证“钩子”。
例如,BMP图像头必须始终以两个字节开始,分别是 'BM'
#[derive(SpRead, SpWrite)]
struct BmpHeader {
#[sp(validate = "validate_header")]
magic: u16,
#[sp(endian="big")]
size: u32,
reserved1: u16,
reserved2: u16,
pixel_array_offset: u32,
// ...
这告诉 simple_parse
在读取时填充 u16
后直接调用 validate_header(magic: &u16, ctx: &mut SpCtx)
,并在写入时将结构体作为字节写入之前。
自定义长度(适用于TLV样式)
simple_parse
通过在元素前简单添加元素数量(len
)来提供动态大小类型的默认实现。
例如,默认情况下,包含三个值的 Vec<u8>
将映射为
// [len] | [len] * [elements]
[3u32][val1][val2][val3]
当解析不遵循此布局的二进制格式时,您可以注释动态大小字段上的 len
pub struct File {
pub content_len: u16,
pub filename: String, // Use the default prepended len
#[sp(len="content_len")]
pub contents: Vec<u8>, // Use an existing field as the len
content_len
字段将用于填充 contents
,并在写入时在该偏移量写入 contents.len()
。
自定义读取/写入
当 simple_parse
的默认读取和写入实现不适合您的格式时,您可以使用 reader
和 writer
属性来覆盖它们。
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)?;
许可证
贡献
除非您明确声明,否则,根据Apache-2.0许可证定义的,您提交的任何有意包含在作品中的贡献,将根据上述条款双许可,无需任何附加条款或条件。
依赖项
~0.7–1.2MB
~26K SLoC