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

0.11.0 2024年4月4日
0.10.1 2023年6月3日
0.10.0 2021年7月24日
0.9.0 2021年7月15日
0.7.1 2020年2月12日

#100#byte-slice

Download history 155/week @ 2024-05-04 138/week @ 2024-05-11 164/week @ 2024-05-18 125/week @ 2024-05-25 129/week @ 2024-06-01 107/week @ 2024-06-08 92/week @ 2024-06-15 109/week @ 2024-06-22 59/week @ 2024-06-29 93/week @ 2024-07-06 86/week @ 2024-07-13 80/week @ 2024-07-20 113/week @ 2024-07-27 95/week @ 2024-08-03 119/week @ 2024-08-10 56/week @ 2024-08-17

每月下载量 392
6 个crate中使用(通过 bitbuffer

MIT/Apache

52KB
1.5K SLoC

自动为struct和enum生成BitReadBitReadSized实现

Structs

只要struct中的每个字段都实现了BitReadBitReadSized,就可以为struct推导出实现。

struct是按定义的顺序逐字段读取的,如果设置了字段的尺寸,将使用stream.read_sized(),否则将使用stream_read()

可以使用3种不同的方法设置字段的尺寸

  • 使用size属性将尺寸设置为整数
  • 使用size属性将先前定义的字段作为尺寸
  • 使用read_bits属性读取指定数量的位作为整数,使用生成的值作为尺寸

当推导出BitReadSized时,可以在尺寸属性中将输入尺寸用作input_size字段。

示例

use bitbuffer::BitRead;

#[derive(BitRead)]
struct TestStruct {
    foo: u8,
    str: String,
    #[size = 2] // when `size` is set, the attributed will be read using `read_sized`
    truncated: String,
    bar: u16,
    float: f32,
    #[size = 3]
    asd: u8,
    #[size_bits = 2] // first read 2 bits as unsigned integer, then use the resulting value as size for the read
    dynamic_length: u8,
    #[size = "asd"] // use a previously defined field as size
    previous_field: u8,
}
use bitbuffer::BitReadSized;

#[derive(BitReadSized, PartialEq, Debug)]
struct TestStructSized {
    foo: u8,
    #[size = "input_size"]
    string: String,
    #[size = "input_size"]
    int: u8,
}

Enums

只要enum的每个变体都没有字段,或者有一个未命名的字段,该字段实现了BitReadBitReadSized,就可以为enum推导出实现。

首先读取一定数量的位作为enum的区分符,然后读取读取的区分符对应的变体。

有关为实现 BitReadSized 的字段设置输入大小的详细信息,请参阅上方 Structs 部分中关于大小的部分。

变体的判别符默认为每个字段递增一,从 0 开始。您可以覆盖字段的判别符,这将同时更改后续每个字段的判别符。

示例

#
#[derive(BitRead)]
#[discriminant_bits = 2]
enum TestBareEnum {
    Foo,
    Bar,
    Asd = 3, // manually set the discriminant value for a field
}
#
#[derive(BitRead)]
#[discriminant_bits = 2]
enum TestUnnamedFieldEnum {
    #[size = 5]
    Foo(i8),
    Bar(bool),
    #[discriminant = 3] // since rust only allows setting the discriminant on field-less enums, you can use an attribute instead
    Asd(u8),
}
#
#[derive(BitReadSized, PartialEq, Debug)]
#[discriminant_bits = 2]
enum TestUnnamedFieldEnumSized {
    #[size = 5]
    Foo(i8),
    Bar(bool),
    #[discriminant = 3]
    #[size = "input_size"]
    Asd(u8),
}

对齐

您可以使用 #[align] 属性请求结构体、枚举或字段的对齐。

#
#[derive(BitRead)]
#[align] // align the reader before starting to read the struct
struct TestAlignStruct {
   #[size = 1]
   foo: u8,
   #[align] // align the reader before reading the field
   bar: u8,
}

它还可以应用于非单元枚举变体

#
#[derive(BitRead)]
#[align] // align the reader before starting to read the enum
#[discriminant_bits = 2]
enum TestAlignEnum {
    Foo(u8),
    #[align] // align the reader before reading the variant (but after reading the discriminant)
    Bar(u8),
}

端序

如果 BitReadBitReadSized 推导的 struct 需要一个 Endianness 类型参数,您需要告诉 derive 宏所使用的类型参数名称

#
#[derive(BitRead)]
#[endianness = "E"]
struct EndiannessStruct<'a, E: Endianness> {
    size: u8,
    #[size = "size"]
    stream: BitReadStream<'a, E>,
}

如果您指定了结构体的端序,这也需要这样做

#
#[derive(BitRead)]
#[endianness = "BigEndian"]
struct EndiannessStruct<'a> {
    size: u8,
    #[size = "size"]
    stream: BitReadStream<'a, BigEndian>,
}

依赖项

~330–780KB
~18K SLoC