14个版本
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日 |
在过程宏中排名197
每月下载量59,514
在44个crate中使用(直接使用10个)
61KB
1.5K SLoC
Rust的位级打包和解包
介绍
位级结构的打包和解包通常是一个需要重新发明轮子的编程任务。这个库提供了一种元编程方法,使用属性来定义字段以及它们应该如何打包。生成的特质实现提供了安全的打包、解包和运行时调试格式化器,并为每个结构生成字段级别的文档。
特性
- 用属性装饰的普通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属性字段,则为必需。 |
端序 |
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 |
enum |
原始枚举的打包助手 |
端序 |
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
依赖关系
~1.5MB
~36K SLoC