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

0.5.0 2024 年 7 月 25 日
0.4.1 2024 年 6 月 13 日
0.3.0 2024 年 3 月 28 日

#995 in 编码

Download history 167/week @ 2024-04-29 139/week @ 2024-05-06 399/week @ 2024-05-13 271/week @ 2024-05-20 341/week @ 2024-05-27 288/week @ 2024-06-03 466/week @ 2024-06-10 316/week @ 2024-06-17 53/week @ 2024-06-24 256/week @ 2024-07-22 18/week @ 2024-07-29

每月 274 次下载

MIT 许可证

67KB
1.5K SLoC

bin-proto

crates tests docs.rs msrv license

简单的 Rust 结构化位级编/解码器。

protocol 的改进和现代化分支。相对于 deku,它更高效(但稍微功能较少)。

此包增加了一个可以应用于类型的特质(以及一个用于易用性的自定义 derive),允许结构化数据从任何二进制流发送和接收。如果您需要位流,建议使用 bitstream_io,因为它们的 BitReadBitWrite 特质正在内部使用。

示例

将以下内容添加到您的 Cargo.toml

[dependencies]
bin-proto = "0.5"

然后定义一个具有 #[derive(bin_proto::ProtocolRead, bin_proto::ProtocolWrite)] 属性的类型。

use bin_proto::{ProtocolRead, ProtocolWrite, ProtocolNoCtx};

#[derive(Debug, ProtocolRead, ProtocolWrite, PartialEq)]
#[protocol(discriminant_type = "u8")]
#[protocol(bits = 4)]
enum E {
    V1 = 1,
    #[protocol(discriminant = "4")]
    V4,
}

#[derive(Debug, ProtocolRead, ProtocolWrite, PartialEq)]
struct S {
    #[protocol(bits = 1)]
    bitflag: bool,
    #[protocol(bits = 3)]
    bitfield: u8,
    enum_: E,
    #[protocol(write_value = "self.arr.len() as u8")]
    arr_len: u8,
    #[protocol(tag = "arr_len as usize")]
    arr: Vec<u8>,
    #[protocol(tag(type = "u16", write_value = "self.prefixed_arr.len() as u16"))]
    prefixed_arr: Vec<u8>,
    #[protocol(flexible_array_member)]
    read_to_end: Vec<u8>,
}

assert_eq!(
    S::from_bytes(&[
        0b1000_0000 // bitflag: true (1)
       | 0b101_0000 // bitfield: 5 (101)
           | 0b0001, // enum_: V1 (0001)
        0x02, // arr_len: 2
        0x21, 0x37, // arr: [0x21, 0x37]
	    0x00, 0x01, 0x33, // prefixed_arr: [0x33]
        0x01, 0x02, 0x03, // read_to_end: [0x01, 0x02, 0x03]
    ], bin_proto::ByteOrder::BigEndian).unwrap(),
    S {
        bitflag: true,
        bitfield: 5,
        enum_: E::V1,
        arr_len: 2,
        arr: vec![0x21, 0x37],
        prefixed_arr: vec![0x33],
        read_to_end: vec![0x01, 0x02, 0x03],
    }
);

您可以在自己的类型上实现 Protocol,并使用上下文进行解析

use bin_proto::{ProtocolRead, ProtocolWrite};

pub struct Ctx;

pub struct NeedsCtx;

impl ProtocolRead<Ctx> for NeedsCtx {
    fn read(
        _read: &mut dyn bin_proto::BitRead,
        _byte_order: bin_proto::ByteOrder,
        _ctx: &mut Ctx,
    ) -> bin_proto::Result<Self> {
        // Use ctx here
        Ok(Self)
    }
}

impl ProtocolWrite<Ctx> for NeedsCtx {
    fn write(
        &self,
        _write: &mut dyn bin_proto::BitWrite,
        _byte_order: bin_proto::ByteOrder,
        _ctx: &mut Ctx,
    ) -> bin_proto::Result<()> {
        // Use ctx here
        Ok(())
    }
}

#[derive(ProtocolRead, ProtocolWrite)]
#[protocol(ctx = "Ctx")]
pub struct WithCtx(NeedsCtx);

WithCtx(NeedsCtx)
    .bytes_ctx(bin_proto::ByteOrder::LittleEndian, &mut Ctx)
    .unwrap();

性能 / 替代方案

此包的主要替代方案是 deku,以及用于字节级协议的 binrw

bin-proto 几乎在所有测试场景中都比 deku 快得多。以下表格的单元是 ns,来自 github CI。您可以在 bench 目录中找到基准测试。

读取 enum 写入 enum 读取 Vec 写入 Vec 读取 IPv4 头 写入 IPv4 头
bin-proto 29 62 1,327 557 173 138
deku 1 92 582 937 3,234 633

路线图

以下功能计划实现

  • 位/字节对齐
  • no_std 支持(仅在 bitstream_io 支持后)

依赖项

~0.4–0.9MB
~20K SLoC