3 个稳定版本
1.2.0 | 2022 年 12 月 11 日 |
---|---|
1.1.0 | 2022 年 11 月 19 日 |
1.0.0 | 2022 年 8 月 14 日 |
#825 在 Rust 模式
38KB
436 行
塔坦位域
此软件包可用于定义具有特定位或位范围访问器的结构。适用于处理寄存器和协议。
功能
- 性能:生成的代码几乎与手动位操作相同。
- 安全性:实现和使用过程中绝对没有不安全代码。
- 可移植性:
#![no_std]
兼容。- 与 C 中的位域不同,布局是可预测的。请参阅下文关于字节序的章节。
- 与 Rust 的
#[repr(packed, C)]
不同,每个字段都有明确的位范围,而不是依赖于结构体内部其他字段的顺序和大小。虽然指定位号可能看起来很麻烦,但它可以消除意外,并且通常直接对应于数据表中寄存器和协议的定义方式。
- 便利性:
- 可以在同一结构中定义单位标志和多位字段。
- 可以使用适当的
Into
和From
实现将位范围作为非原语、非整型类型(包括其他位域结构)访问。 - 这些结构实现了您期望的所有特质。请参阅
bitfield
的文档。如果需要提供自己的调试输出,还有一个bitfield_without_debug
宏。 - 可以在特质中定义访问器,这对于某些字段是常见,但其他字段只在特定状态下定义的寄存器很有用。请参阅
bitfield_accessors
。
示例
bitfield! {
// The structure will be a wrapper for a u32 value.
pub struct Example(u32) {
// Accessors for field `a` will refer to the first four least significant
// bits of the wrapped value, bits 0, 1, 2, and 3.
//
// Note that like normal Rust ranges:
// * `[0..4]` does not include bit 4
// * `[0..=4]` includes bit 4
//
// The accessors will be public, and will take/return the four bits as a `u8`.
[0..4] pub a: u8,
// No accessors cover bits `4..6`. This is legal and can be used for reserved
// bits. However, these bits will still affect equality for the struct as a
// whole.
// Accessors for field `b` will refer to the twelve bits starting at bit 6,
// but they will not be public. They will take/return the 12 bits as a `u16`.
[6..=17] b: u16,
// Note that this bit range overlaps with `b`. This is allowed.
[16..20] pub c: u8,
// Accessors for field `d` will take/return a boolean and refer to a single
// bit. Note that the `bool` is implied and not specified after the name.
[25] pub d,
// This will cover the 6 most significant bits of the wrapped value, but
// the getters will take/return a `SubFields` struct instead of `u8`. This is
// useful for nested bitfields, but the `A as B` syntax works for any `B`
// which implements `Into<A>` and `From<A>`.
[26..32] pub e: u8 as SubFields,
}
}
bitfield! {
// All accessors on this field use booleans and refer to single bits
pub struct SubFields(u8) {
[0] pub zero,
[1] pub one,
[2] pub two,
[3] pub three,
[4] pub four,
[5] pub five,
}
}
// The struct can be initialized with a u32 value
let x = Example(0xfa84_9e1b);
assert_eq!(x.a(), 0xb_u8);
assert_eq!(x.b(), 0x278_u16); // Private, but still can be used within the module
assert_eq!(x.c(), 0x4_u8);
assert_eq!(x.d(), true);
assert_eq!(x.e(), SubFields(0x3e_u8));
assert_eq!(x.e().zero(), false);
assert_eq!(x.e().five(), true);
// It can also be converted Into and From its underlying representation
let n: u32 = x.into();
let y: Example = n.into();
assert_eq!(n, 0xfa84_9e1b);
assert_eq!(x, y);
// Setters are all prefixed with `set_`. They have the same visibility as the getters.
let mut z = Example::default();
z.set_a(0xb);
z.set_b(0x278);
z.set_c(0x4);
z.set_d(true);
z.set_e(SubFields(0x3e));
assert_eq!(z, Example(0xfa04_9e0b));
// Reserved ranges influence equality, and they are all zero on `z`.
assert_ne!(z, x);
// Alternatively, you can use the `with_` methods, which return a new value instead
// of mutating in place.
let mut w = x
.with_a(0x6)
.with_b(0x9f3)
.with_c(0xd)
.with_d(false)
.with_e(SubFields(0x2b));
assert_eq!(w, Example(0xac8d_7cd6));
assert_eq!(x, Example(0xfa84_9e1b));
更多示例,请参阅从这个crate衍生出来的Tartan OS项目。
字节序和位编号
每个位域封装一个基本整数类型。在上面的例子中,Example(u32)
封装了一个u32
。宏中的位编号指的是逻辑值的位,从最低有效位开始计数=0。它们不依赖于u32
在内存中表示的字节顺序,即字节序。
底层值的字节序取决于平台。这与任何其他整数值没有不同,上下文决定你是否需要担心它。
- 如果底层表示是
u8
,则字节顺序无关紧要。 - 如果你正在从寄存器读取,你很可能想要使用本地字节顺序,不需要做任何特殊处理。
- 如果你正在处理网络或总线协议,你很可能是在从字节数组进行序列化或反序列化。要使用特定字节序进行转换,而不考虑平台,请使用常规方法:例如,内置函数
u32::from_be_bytes
和u64::to_le_bytes
,或者使用byteorder这样的crate。
替代方案
我已经在我的个人OS项目中使用了一段时间,它比其他选项更好地满足了我的需求。但是,你可能对一些其他crate感兴趣
- bitfield:类似访问器和位范围的方法,但语法不那么明显。
- bitflags:适用于将单个位标志视为集合的情况。
- bitvec:另一种将内存视为一系列位的集合类型。不太关注定义特定领域的结构体。
- modular-bitfield:字段顺序和宽度确定位范围。结构体只能转换为字节数组,并且只能按小端序转换,无论平台字节序如何。这可能在处理寄存器时不受欢迎。
- packed_struct:提供了许多选项,包括位编号和字节序转换。结构体以非打包形式存储在内存中,仅在序列化时转换为打包形式。根据你的访问模式,这可能更好或更差(或者可能根本无关紧要)。
- 有关
pack_struct
的PrimitiveEnum
的类似物,请参阅tartan-c-enum
crate。
- 有关
安装
将其添加到你的Cargo.toml文件中
[dependencies]
tartan-bitfield = 1.2.0
开发
这是一个相当标准的Rust库,使用Cargo进行开发。
测试
cargo test --all-targets
基准测试
cargo bench
格式化/代码检查
cargo fmt
cargo clippy --all-targets
许可证
许可协议为以下之一
- Apache许可证2.0版本(LICENSE-APACHE或http://www.apache.org/licenses/LICENSE-2.0)
- MIT许可证(LICENSE-MIT或http://opensource.org/licenses/MIT)
任由您选择。
贡献
除非您明确声明,否则根据Apache-2.0许可证定义,您有意提交的任何贡献,用于包含在本工作中,将按上述方式双授权,不附加任何额外条款或条件。
此README是从文档注释生成的。使用cargo readme
来刷新它。