28个版本
0.8.0 | 2024年6月20日 |
---|---|
0.6.2 | 2024年5月23日 |
0.6.0 | 2024年2月16日 |
0.5.6 | 2023年12月10日 |
0.1.1 | 2021年12月28日 |
#98 in 数据结构
47,093 个月的下载量
在 65 个crate中使用 (35个直接使用)
44KB
836 行
位域结构体
允许将位域指定为结构体的过程宏。因为这个库提供了一个过程宏,所以它没有运行时依赖项,并且适用于 no-std
环境。
- 非常适合驱动程序/操作系统/嵌入式开发(定义硬件寄存器/结构)
- 支持布尔标志、整数以及可转换为整数的自定义类型(结构体/枚举)
- 生成最小化、纯、安全的Rust函数
- 编译时检查类型和字段大小
- Rust-analyzer/docrs友好(将文档传递给访问器函数)
- 将字段偏移和大小作为常量导出(对const断言很有用)
- 生成
Default
、fmt::Debug
或defmt::Format
特性 - 自定义内部表示(字节序)
用法
将此添加到您的 Cargo.toml
[dependencies]
bitfield-struct = "0.7"
基础
让我们从一个简单的例子开始。假设我们想在单个字节中存储多个数据,如下所示
7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
P | 级别 | S | 种类 |
此crate生成一个很好的包装类型,使得这样做变得容易
use bitfield_struct::bitfield;
/// Define your type like this with the bitfield attribute
#[bitfield(u8)]
struct MyByte {
/// The first field occupies the least significant bits
#[bits(4)]
kind: usize,
/// Booleans are 1 bit large
system: bool,
/// The bits attribute specifies the bit size of this field
#[bits(2)]
level: usize,
/// The last field spans over the most significant bits
present: bool
}
// The macro creates three accessor functions for each field:
// <name>, with_<name> and set_<name>
let my_byte = MyByte::new()
.with_kind(15)
.with_system(false)
.with_level(3)
.with_present(true);
assert!(my_byte.present());
特性
此外,此crate还有一些有用的特性,以下将详细介绍。
以下示例显示了如何传递属性以及如何处理有符号整数、填充和自定义类型。
use bitfield_struct::bitfield;
/// A test bitfield with documentation
#[bitfield(u64)]
#[derive(PartialEq, Eq)] // <- Attributes after `bitfield` are carried over
struct MyBitfield {
/// Defaults to 16 bits for u16
int: u16,
/// Interpreted as 1 bit flag, with a custom default value
#[bits(default = true)]
flag: bool,
/// Custom bit size
#[bits(1)]
tiny: u8,
/// Sign extend for signed integers
#[bits(13)]
negative: i16,
/// Supports any type with `into_bits`/`from_bits` functions
#[bits(16)]
custom: CustomEnum,
/// Public field -> public accessor functions
#[bits(10)]
pub public: usize,
/// Also supports read-only fields
#[bits(1, access = RO)]
read_only: bool,
/// And write-only fields
#[bits(1, access = WO)]
write_only: bool,
/// Padding
#[bits(5)]
__: u8,
}
/// A custom enum
#[derive(Debug, PartialEq, Eq)]
#[repr(u16)]
enum CustomEnum {
A = 0,
B = 1,
C = 2,
}
impl CustomEnum {
// This has to be a const fn
const fn into_bits(self) -> u16 {
self as _
}
const fn from_bits(value: u16) -> Self {
match value {
0 => Self::A,
1 => Self::B,
_ => Self::C,
}
}
}
// Usage:
let mut val = MyBitfield::new()
.with_int(3 << 15)
.with_tiny(1)
.with_negative(-3)
.with_custom(CustomEnum::B)
.with_public(2)
// .with_read_only(true) <- Would not compile
.with_write_only(false);
println!("{val:?}");
let raw: u64 = val.into();
println!("{raw:b}");
assert_eq!(val.int(), 3 << 15);
assert_eq!(val.flag(), true);
assert_eq!(val.negative(), -3);
assert_eq!(val.tiny(), 1);
assert_eq!(val.custom(), CustomEnum::B);
assert_eq!(val.public(), 2);
assert_eq!(val.read_only(), false);
// const members
assert_eq!(MyBitfield::FLAG_BITS, 1);
assert_eq!(MyBitfield::FLAG_OFFSET, 16);
val.set_negative(1);
assert_eq!(val.negative(), 1);
宏为每个字段生成三个访问器函数。每个访问器也继承了其字段的文档。
int
的签名是
use std::fmt::{Debug, Formatter, Result};
// generated struct
struct MyBitfield(u64);
impl MyBitfield {
const fn new() -> Self { Self(0) }
const INT_BITS: usize = 16;
const INT_OFFSET: usize = 0;
const fn with_int(self, value: u16) -> Self { todo!() }
const fn int(&self) -> u16 { todo!() }
fn set_int(&mut self, value: u16) { todo!() }
// other field ...
}
// Also generates From<u64>, Into<u64>, Default, and Debug implementations...
提示:您可以使用rust-analyzer的“递归展开宏”操作来查看生成的代码。
自定义类型
此宏支持任何可以转换为底层位域类型的类型。这可以是以下示例中的枚举或其他任何结构体。
可以使用以下 #[bits]
参数来指定转换和默认值:
from
:将原始位转换为自定义类型的函数,默认为<ty>::from_bits
into
:将自定义类型转换为原始位的函数,默认为<ty>::into_bits
default
:自定义表达式,默认为调用<ty>::from_bits(0)
use bitfield_struct::bitfield;
#[bitfield(u16)]
#[derive(PartialEq, Eq)]
struct Bits {
/// Supports any convertible type
#[bits(8, default = CustomEnum::B, from = CustomEnum::my_from_bits)]
custom: CustomEnum,
/// And nested bitfields
#[bits(8)]
nested: Nested,
}
#[derive(Debug, PartialEq, Eq)]
#[repr(u8)]
enum CustomEnum {
A = 0,
B = 1,
C = 2,
}
impl CustomEnum {
// This has to be a const fn
const fn into_bits(self) -> u8 {
self as _
}
const fn my_from_bits(value: u8) -> Self {
match value {
0 => Self::A,
1 => Self::B,
_ => Self::C,
}
}
}
/// Bitfields implement the conversion functions automatically
#[bitfield(u8)]
struct Nested {
#[bits(4)]
lo: u8,
#[bits(4)]
hi: u8,
}
字段顺序
可选的 order
宏参数确定位的布局,默认为 Lsb(最低有效位)优先
use bitfield_struct::bitfield;
#[bitfield(u8, order = Lsb)]
struct MyLsbByte {
/// The first field occupies the *least* significant bits
#[bits(4)]
kind: usize,
system: bool,
#[bits(2)]
level: usize,
present: bool
}
let my_byte_lsb = MyLsbByte::new()
.with_kind(10)
.with_system(false)
.with_level(2)
.with_present(true);
// .- present
// | .- level
// | | .- system
// | | | .- kind
assert_eq!(my_byte_lsb.0, 0b1_10_0_1010);
当指定 Msb(最高有效位)时,宏生成逆序
use bitfield_struct::bitfield;
#[bitfield(u8, order = Msb)]
struct MyMsbByte {
/// The first field occupies the *most* significant bits
#[bits(4)]
kind: usize,
system: bool,
#[bits(2)]
level: usize,
present: bool
}
let my_byte_msb = MyMsbByte::new()
.with_kind(10)
.with_system(false)
.with_level(2)
.with_present(true);
// .- kind
// | .- system
// | | .- level
// | | | .- present
assert_eq!(my_byte_msb.0, 0b1010_0_10_1);
自定义表示和字节序
该宏支持用于表示位域结构的自定义类型。这可以是一个字节序定义类型,如以下示例所示(来自 endian-num
)或任何可以转换为和从主位域类型转换的任何其他结构。
可以使用以下 #[bitfield]
参数来指定表示及其转换函数:
repr
指定位域在内存中的表示from
指定一个从表示到位域整型的转换函数into
指定一个从位域整型到表示的转换函数
此示例即使在大端机器上也有小端字节序
use bitfield_struct::bitfield;
use endian_num::le16;
#[bitfield(u16, repr = le16, from = le16::from_ne, into = le16::to_ne)]
struct MyLeBitfield {
#[bits(4)]
first_nibble: u8,
#[bits(12)]
other: u16,
}
let my_be_bitfield = MyLeBitfield::new()
.with_first_nibble(0x1)
.with_other(0x234);
assert_eq!(my_be_bitfield.into_bits().to_le_bytes(), [0x41, 0x23]);
此示例即使在小端机器上也有大端字节序
use bitfield_struct::bitfield;
use endian_num::be16;
#[bitfield(u16, repr = be16, from = be16::from_ne, into = be16::to_ne)]
struct MyBeBitfield {
#[bits(4)]
first_nibble: u8,
#[bits(12)]
other: u16,
}
let my_be_bitfield = MyBeBitfield::new()
.with_first_nibble(0x1)
.with_other(0x234);
assert_eq!(my_be_bitfield.into_bits().to_be_bytes(), [0x23, 0x41]);
自动实现特质
此宏自动创建一个合适的 fmt::Debug
和 Default
实现,类似于由 #[derive(Debug, Default)]
为普通结构创建的实现。您可以通过额外的 debug
和 default
参数来禁用此功能。
use std::fmt::{Debug, Formatter, Result};
use bitfield_struct::bitfield;
#[bitfield(u64, debug = false, default = false)]
struct CustomDebug {
data: u64
}
impl Debug for CustomDebug {
fn fmt(&self, f: &mut Formatter<'_>) -> Result {
write!(f, "0x{:x}", self.data())
}
}
impl Default for CustomDebug {
fn default() -> Self {
Self(123)
}
}
let val = CustomDebug::default();
println!("{val:?}")
支持 defmt::Format
此宏可以通过传递额外的 defmt
参数自动实现一个 defmt::Format
,该实现类似于通过传递额外的 defmt
参数传递的默认 fmt::Debug
实现。此实现需要 defmt crate 以 defmt
的形式可用,并具有与 #[derive(defmt::Format)]
相同的规则和注意事项。
use bitfield_struct::bitfield;
#[bitfield(u64, defmt = true)]
struct DefmtExample {
data: u64
}
有条件地启用 Debug
/Default
/defmt::Format
您可以为 debug
、default
和 defmt
指定 cfg(...)
属性,而不是布尔值。
use bitfield_struct::bitfield;
#[bitfield(u64, debug = cfg(test), default = cfg(feature = "foo"))]
struct CustomDebug {
data: u64
}
依赖项
~265–710KB
~17K SLoC