#binary-format #binary #binary-encoding #codec #deserialize #encode #binary-data

bin-layout

该库用于二进制格式中数据的序列化和反序列化

13 个版本 (6 个重大变更)

7.1.0 2022 年 10 月 2 日
6.0.0 2022 年 7 月 29 日
5.1.0 2022 年 4 月 15 日
4.0.1 2022 年 4 月 5 日
0.2.0 2022 年 3 月 9 日

#1386编码

每月 28 次下载

Apache-2.0

35KB
781

文档

非常快!而且灵活,该库用于二进制格式中数据的序列化和反序列化。

字节序

默认情况下,库使用小端字节序。如果您想使用大端字节序,可以设置 BE 特性标志。对于本地字节序,使用 NE。例如

[dependencies]
bin-layout = { version = "7", features = ["BE"] }

示例

use bin_layout::*;

#[derive(Encoder, Decoder)]
struct Car<'a> {
    year: u16,
    is_new: bool,
    name: &'a str,
}

#[derive(Encoder, Decoder)]
struct Company<'a> { name: String, cars: Vec<Car<'a>> }

let old = Company {
    name: "Tesla".into(),
    cars: vec![
        Car { name: "Model S", year: 2018, is_new: true },
        Car { name: "Model X", year: 2019, is_new: false },
    ],
};
let bytes = old.encode();
let new = Company::decode(&bytes);
  • 零拷贝反序列化:意味着没有数据被复制。动态长度数据(VecString&[T]&str 等)首先编码它们的长度值,然后编码每个条目。
use bin_layout::*;

#[derive(Encoder, Decoder)]
struct Msg<'a> {
    id: u8,
    data: &'a str,
}
let bytes = [42, 13, 72, 101, 108, 108, 111, 44, 32, 87, 111, 114, 108, 100, 33];
//           ^^  ^^  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
//           Id  Len                         Data

let msg = Msg::decode(&bytes).unwrap();
assert_eq!(msg.id, 42);
assert_eq!(msg.data, "Hello, World!"); // Here, data is referenced.
  • 在这个示例中,以下结构体不包含任何动态长度数据。因此,我们可以在编译时有一个固定大小的缓冲区。
use bin_layout::*;

#[derive(Encoder, Decoder)]
struct Date {
    year: u16,
    month: u8,
    day: u8,
}

#[derive(Encoder, Decoder)]
struct Record {
    id: u32,
    date: Date,
    value: [u8; 512],
}

let record = Record { id: 42, date: Date { year: 2018, month: 3, day: 7 }, value: [1; 512] };
let mut writer = [0; 520];
record.encoder(&mut writer.as_mut_slice());
  • 实现 EncoderDecoder 特征非常简单。例如
use std::io;
use bin_layout::*;

type DynErr = Box<dyn std::error::Error + Send + Sync>;

#[derive(Encoder, Decoder)]
struct Bar(u16);
struct Foo { x: u8, y: Bar }

impl Encoder for Foo {
    fn encoder(&self, c: &mut impl io::Write) -> io::Result<()> {
        self.x.encoder(c)?;
        self.y.encoder(c)
    }
}
impl Decoder<'_> for Foo {
    fn decoder(c: &mut &[u8]) -> Result<Self, DynErr> {
        Ok(Self {
            x: u8::decoder(c)?,
            y: Bar::decoder(c)?,
        })
    }
}

可变长度整数编码

此编码确保较小的整数值需要较少的字节进行编码。支持类型为 L2L3,两者都使用小端字节序进行编码。

默认情况下,使用 L3(u22)来编码记录的长度(整数)。但您可以通过在特性标志中设置 L2(u15)来覆盖它。

编码算法非常简单,保留第一个字节的一个或两个最高有效位来编码剩余的长度。

L2

MSB 长度 可用位 范围
0 1 7 0..128
1 2 15 0..32768

L3

MSB 长度 可用位 范围
0 1 7 0..128
10 2 14 0..16384
11 3 22 0..4194304

例如,0x_C0DE 的二进制表示为 0x_11_00000011_011110

L3(0x_C0DE) 编码为 3 个字节

1st byte: 11_011110      # MSB is 11, so read next 2 bytes
2nd byte:        11
3rd byte:        11

另一个示例,L3(107) 仅占用 1 个字节进行编码

1st byte: 0_1101011      # MSB is 0, So we don't have to read extra bytes.

固定长度集合

Record 可以用来编码长度大小已知的集合。

例如,Record<u8, String> 这里最大允许的有效负载长度为 255 (u8::MAX)

依赖项

~1.5MB
~35K SLoC