14 个版本 (7 个重大变化)
0.10.1 | 2022年11月16日 |
---|---|
0.10.0 | 2021年9月15日 |
0.6.1 | 2021年9月10日 |
0.6.0 | 2021年6月27日 |
0.2.3 | 2018年3月29日 |
#79 in 编码
59,582 每月下载量
在 43 个 crate (26 directly) 中使用
90KB
1.5K SLoC
Rust 的位级打包和解包
简介
位级结构的打包和解包通常是重新发明轮子的编程任务。此库提供了一种元编程方法,使用属性来定义字段及其打包方式。生成的 trait 实现提供安全的打包、解包和运行时调试格式化程序,并为每个结构体生成字段文档。
功能
- 带属性的普通 Rust 结构体
- 用户定义位宽的 MSB 或 LSB 整数
- 原始枚举代码生成辅助工具
- MSB0 或 LSB0 位定位
- 记录字段的打包表
- 运行时打包可视化
- 嵌套打包类型
- 作为字段的打包结构体数组
- 保留字段,它们的位总是 0 或 1
crate 级功能标志
std
: 使用 Rust 标准库。默认。alloc
: 在no_std
+alloc
场景下使用alloc
crate。需要 nightly Rust。use_serde
: 向内置辅助类型添加序列化支持。byte_types_64
,byte_types_256
: 扩大生成的数组、字节和位宽类型的大小。
示例用法
Cargo.toml
[dependencies]
packed_struct = "0.10"
导入具有最常见特性和 derive 宏的库
// This is only needed for pre Rust 2018
#[macro_use] extern crate packed_struct;
// Prelude import with the common imports
use packed_struct::prelude::*;
单个字节结构的示例,包含 3 位整数、原始枚举和布尔字段。
use packed_struct::prelude::*;
#[derive(PackedStruct)]
#[packed_struct(bit_numbering="msb0")]
pub struct TestPack {
#[packed_field(bits="0..=2")]
tiny_int: Integer<u8, packed_bits::Bits::<3>>,
#[packed_field(bits="3..=4", ty="enum")]
mode: SelfTestMode,
#[packed_field(bits="7")]
enabled: bool
}
#[derive(PrimitiveEnum_u8, Clone, Copy, Debug, PartialEq)]
pub enum SelfTestMode {
NormalMode = 0,
PositiveSignSelfTest = 1,
NegativeSignSelfTest = 2,
DebugMode = 3,
}
fn main() -> Result<(), PackingError> {
let test = TestPack {
tiny_int: 5.into(),
mode: SelfTestMode::DebugMode,
enabled: true
};
// pack into a byte array
let packed: [u8; 1] = test.pack()?;
assert_eq!([0b10111001], packed);
// unpack from a byte array
let unpacked = TestPack::unpack(&packed)?;
assert_eq!(*unpacked.tiny_int, 5);
assert_eq!(unpacked.mode, SelfTestMode::DebugMode);
assert_eq!(unpacked.enabled, true);
// or unpack from a slice
let unpacked = TestPack::unpack_from_slice(&packed[..])?;
Ok(())
}
打包属性
语法
use packed_struct::prelude::*;
#[derive(PackedStruct)]
#[packed_struct(attr1="val", attr2="val")]
pub struct Structure {
#[packed_field(attr1="val", attr2="val")]
field: u8
}
每个结构体的属性
属性 | 值 | 注释 |
---|---|---|
size_bytes |
1 ... n |
打包字节流的长度 |
bit_numbering |
msb0 或 lsb0 |
字段位定位的位编号。如果使用 bits 属性字段,则必须指定。 |
endian |
msb 或 lsb |
默认整数字节序 |
每个字段的属性
属性 | 值 | 注释 |
---|---|---|
bits |
0 , 0..1 , ... |
字段在打包结构体中的位置。支持三种模式:单个位、起始位或位范围。详见下文。 |
bytes |
0 , 0..1 , ... |
与上面相同,乘以 8。 |
size_bits |
1 , ... |
指定打包结构的尺寸。对于某些类型是必需的。指定一个位范围,如 bits="0..2" 可以替代使用 size_bits 的需求。 |
size_bytes |
1 , ... |
与上面相同,乘以 8。 |
element_size_bits |
1 , ... |
对于打包数组,指定数组中单个元素的尺寸。明确声明整个数组的尺寸可以替代使用此属性。 |
element_size_bytes |
1 , ... |
与上面相同,乘以 8。 |
ty |
枚举 |
原始枚举的打包助手。 |
endian |
msb 或 lsb |
整数字节序。适用于 u16/i16 和更大的类型。 |
位和字节定位
用于字段上的 bits
或 bytes
。以下示例为 MSB0 定位。
值 | 注释 |
---|---|
0 |
单个位或字节 |
0.. , 0: |
字段从零位开始 |
0..2 |
排他性范围,位零和一 |
0:1 , 0..=1 |
包含性范围,位零和一 |
更多示例
混合字节序的整数
use packed_struct::prelude::*;
#[derive(PackedStruct)]
pub struct EndianExample {
#[packed_field(endian="lsb")]
int1: u16,
#[packed_field(endian="msb")]
int2: i32
}
fn main() -> Result<(), PackingError> {
let example = EndianExample {
int1: 0xBBAA,
int2: 0x11223344
};
let packed = example.pack()?;
assert_eq!([0xAA, 0xBB, 0x11, 0x22, 0x33, 0x44], packed);
Ok(())
}
24位LSB整数
use packed_struct::prelude::*;
#[derive(PackedStruct)]
#[packed_struct(endian="lsb")]
pub struct LsbIntExample {
int1: Integer<u32, packed_bits::Bits::<24>>,
}
fn main() -> Result<(), PackingError> {
let example = LsbIntExample {
int1: 0xCCBBAA.into()
};
let packed = example.pack()?;
assert_eq!([0xAA, 0xBB, 0xCC], packed);
Ok(())
}
嵌套打包类型
use packed_struct::prelude::*;
#[derive(PackedStruct, Debug, PartialEq)]
#[packed_struct(endian="lsb")]
pub struct Duration {
minutes: u8,
seconds: u8,
}
#[derive(PackedStruct, Debug, PartialEq)]
pub struct Record {
#[packed_field(element_size_bytes="2")]
span: Duration,
events: u8,
}
fn main() -> Result<(), PackingError> {
let example = Record {
span: Duration {
minutes: 10,
seconds: 34,
},
events: 3,
};
let packed = example.pack()?;
let unpacked = Record::unpack(&packed)?;
assert_eq!(example, unpacked);
Ok(())
}
数组中的嵌套打包类型
use packed_struct::prelude::*;
#[derive(PackedStruct, Default, Debug, PartialEq)]
#[packed_struct(bit_numbering="msb0")]
pub struct TinyFlags {
_reserved: ReservedZero<packed_bits::Bits::<4>>,
flag1: bool,
val1: Integer<u8, packed_bits::Bits::<2>>,
flag2: bool
}
#[derive(PackedStruct, Debug, PartialEq)]
pub struct Settings {
#[packed_field(element_size_bits="4")]
values: [TinyFlags; 4]
}
fn main() -> Result<(), PackingError> {
let example = Settings {
values: [
TinyFlags { flag1: true, val1: 1.into(), flag2: false, .. TinyFlags::default() },
TinyFlags { flag1: true, val1: 2.into(), flag2: true, .. TinyFlags::default() },
TinyFlags { flag1: false, val1: 3.into(), flag2: false, .. TinyFlags::default() },
TinyFlags { flag1: true, val1: 0.into(), flag2: false, .. TinyFlags::default() },
]
};
let packed = example.pack()?;
let unpacked = Settings::unpack(&packed)?;
assert_eq!(example, unpacked);
Ok(())
}
具有简单区分符的原始枚举
支持的底层整数类型:u8
、u16
、u32
、u64
、i8
、i16
、i32
、i64
。
显式或隐式底层类型
use packed_struct::prelude::*;
#[derive(PrimitiveEnum, Clone, Copy, PartialEq, Debug)]
pub enum ImplicitType {
VariantMin = 0,
VariantMax = 255
}
#[derive(PrimitiveEnum_i16, Clone, Copy)]
pub enum ExplicitType {
VariantMin = -32768,
VariantMax = 32767
}
fn main() {
use packed_struct::PrimitiveEnum;
let t = ImplicitType::VariantMin;
let tn: u8 = t.to_primitive();
assert_eq!(0, tn);
let t = ImplicitType::from_primitive(255).unwrap();
assert_eq!(ImplicitType::VariantMax, t);
}
支持捕获所有未知值的原始枚举打包
use packed_struct::prelude::*;
#[derive(PrimitiveEnum_u8, Debug, Clone, Copy)]
pub enum Field {
A = 1,
B = 2,
C = 3
}
#[derive(PackedStruct, Debug, PartialEq)]
#[packed_struct(bit_numbering="msb0")]
pub struct Register {
#[packed_field(bits="0..4", ty="enum")]
field: EnumCatchAll<Field>
}
许可:MIT OR Apache-2.0
依赖项
~2.5MB
~60K SLoC