#位域 #标志 #访问器 #范围 #结构 #定义 #布局

无需 std 塔坦位域

定义具有特定位或位范围访问器的结构

3 个稳定版本

1.2.0 2022 年 12 月 11 日
1.1.0 2022 年 11 月 19 日
1.0.0 2022 年 8 月 14 日

#825Rust 模式

MIT/Apache

38KB
436

塔坦位域

Crate Docs Build License

此软件包可用于定义具有特定位或位范围访问器的结构。适用于处理寄存器和协议。

功能

  • 性能:生成的代码几乎与手动位操作相同。
  • 安全性:实现和使用过程中绝对没有不安全代码。
  • 可移植性:
    • #![no_std] 兼容。
    • 与 C 中的位域不同,布局是可预测的。请参阅下文关于字节序的章节。
    • 与 Rust 的 #[repr(packed, C)] 不同,每个字段都有明确的位范围,而不是依赖于结构体内部其他字段的顺序和大小。虽然指定位号可能看起来很麻烦,但它可以消除意外,并且通常直接对应于数据表中寄存器和协议的定义方式。
  • 便利性:
    • 可以在同一结构中定义单位标志和多位字段。
    • 可以使用适当的 IntoFrom 实现将位范围作为非原语、非整型类型(包括其他位域结构)访问。
    • 这些结构实现了您期望的所有特质。请参阅 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_bytesu64::to_le_bytes,或者使用byteorder这样的crate。

替代方案

我已经在我的个人OS项目中使用了一段时间,它比其他选项更好地满足了我的需求。但是,你可能对一些其他crate感兴趣

  • bitfield:类似访问器和位范围的方法,但语法不那么明显。
  • bitflags:适用于将单个位标志视为集合的情况。
  • bitvec:另一种将内存视为一系列位的集合类型。不太关注定义特定领域的结构体。
  • modular-bitfield:字段顺序和宽度确定位范围。结构体只能转换为字节数组,并且只能按小端序转换,无论平台字节序如何。这可能在处理寄存器时不受欢迎。
  • packed_struct:提供了许多选项,包括位编号和字节序转换。结构体以非打包形式存储在内存中,仅在序列化时转换为打包形式。根据你的访问模式,这可能更好或更差(或者可能根本无关紧要)。
    • 有关pack_structPrimitiveEnum的类似物,请参阅tartan-c-enumcrate。

安装

将其添加到你的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许可证定义,您有意提交的任何贡献,用于包含在本工作中,将按上述方式双授权,不附加任何额外条款或条件。


此README是从文档注释生成的。使用cargo readme来刷新它。

依赖项