#位字段 #bitflags #bits #bit #位字段 #整数值 #操作系统

无std mycelium-bitfield

由Mycelium提供的结构化位字段

6个版本

0.1.5 2024年1月21日
0.1.4 2023年11月28日
0.1.3 2023年7月23日
0.1.2 2022年7月25日

97编码 中排名

Download history 161/week @ 2024-04-07 133/week @ 2024-04-14 99/week @ 2024-04-21 189/week @ 2024-04-28 86/week @ 2024-05-05 84/week @ 2024-05-12 166/week @ 2024-05-19 130/week @ 2024-05-26 319/week @ 2024-06-02 332/week @ 2024-06-09 142/week @ 2024-06-16 135/week @ 2024-06-23 429/week @ 2024-06-30 532/week @ 2024-07-07 469/week @ 2024-07-14 356/week @ 2024-07-21

每月 1,787 次下载
3 个crate中使用(通过 maitake-sync

MIT 许可证

125KB
1.5K SLoC

mycelium-bitfield

🍄 位字段实用工具,由Mycelium提供。

crates.io Documentation Documentation (HEAD) MIT licensed Test Status Sponsor @hawkw on GitHub Sponsors

这是什么?

此库提供在Rust中定义结构化位字段的实用工具。它包含一组用于定义可以打包和从整数值解包的范围的类型,以及一个用于使用打包类型自动生成位字段类型的宏 bitfield!。这些组件是模块化的:可以使用打包规范类型手动编写宏 bitfield! 会生成的所有代码。

这个crate最初是为在 Mycelium操作系统 中使用而实现的,尽管它也可以用于其他项目,并且不依赖于任何Mycelium特定的库。

注意

这是一个兴趣项目。我在业余时间做这个,供自己使用。我很高兴与更广泛的Rust社区分享,并且始终欢迎 贡献错误报告。然而,请记住,我是在 玩乐 中构建这个库,如果它不再有趣……好吧,你明白了。

无论如何,请随意使用并享受这个crate,并根据你的意愿进行尽可能多的贡献!

与其他crate的比较

还有其他几个crate在Rust中实现了位字段或与位字段相关的实用工具。这些crate提供与 mycelium-bitfield 不同,但有时重叠的功能。特别是,目前我所知道的最直接可比的crate是 modular-bitfieldbitflags 库。

注意 该软件包存在主要是因为我认为编写自己的位域软件包很有趣,而不是因为现有的库有缺陷。我对于“有趣”可能有一些扭曲的认识...

特别是,modular-bitfield 软件包可以执行与 mycelium-bitfield 相似的大部分操作。然而,这两个库之间有一些差异,可能值得考虑。

  • bitflags:该 bitflags 软件包提供了一种声明性宏,用于生成表示一组位标志的结构化类型。

    bitflagsbitflags! 宏与 mycelium-bitfieldbitfield! 宏之间的关键区别是,bitflags 软件包仅实现了位标志,而不是位。无法使用 bitflags 定义多位的结构化范围;只能设置和清除单个位的标志。

    然而,bitflags 软件包被广泛使用,存在很长时间,相对简单且轻量级。如果您只需要一组布尔型、单位的标志,它是一个非常好的选择。但是,如果您需要 mycelium-bitfield 在处理多位范围方面的附加功能,请注意它也可以执行大多数 bitflags 软件包可以执行的操作。

  • modular-bitfield:该 modular-bitfield 软件包提供了一种过程宏,用于生成带类型的结构化位域。

    modular-bitfield 实现的功能与 mycelium-bitfield 非常相似——这两个库可以做大部分相同的事情。

    主要区别在于,modular-bitfield 使用过程宏属性实现,而 mycelium-bitfieldbitfield! 宏是一个声明性宏。在我看来,这并不是在大多数情况下更喜欢 mycelium-bitfield 而不是 modular-bitfield 的理由。我决定尝试使用声明性宏来编写整个软件包,因为我认为这将是一个有趣的挑战,而不是因为它更好(实际上,使用过程宏实现位域类型生成可能会更容易)。然而,如果用户需要出于某些原因减少或避免过程宏,可能需要考虑出于这个原因选择 mycelium-bitfield

    modular-bitfield相比,mycelium-bitfield的主要区别在于,它还提供了包含打包规范类型的pack模块。这些类型可以用于“手动”构建位域类型,在需要与宏生成的代码不同的行为时使用。modular-bitfield仅提供过程宏,并且没有与此低级接口等效的功能。

    另一方面,modular-bitfield提供了更友好的验证,以确保用作位域一部分的类型实际上适合该位域。mycelium-bitfield目前无法进行此类编译时检查,而是依赖于用户提供的类型实现FromBits特质的正确性。

使用方法

本软件包的API由三个主要组件组成,即打包规范类型bitfield! FromBits特质。

打包规范类型

pack模块定义了一组类型,可用于打包和解包各种大小整数的范围,例如,Pack64用于打包和解包从u64值得到的范围。

这些打包规范类型具有const fn构造函数,允许它们相互关联地定义。例如

use mycelium_bitfield::Pack64;

// Defines a packing spec for the least-significant 12 bits of a 64-bit value.
const LOW: Pack64 = Pack64::least_significant(12);
// Defines a packing spec for the next 8 more-significant bits after `LOW`.
const MID: Pack64 = LOW.next(8);
// Defines a packing spec for the next 4 more-significant bits after `MID`.
const HIGH: Pack64 = MID.next(4);

// Wrap an integer value to pack it using method calls.
let coffee = Pack64::pack_in(0)
    // pack the 12 bits of `0xfee` at the range specified by `LOW`.
    .pack(0xfee, &LOW)
    // pack the 4 bits `0xc` at the range specified by `HIGH`.
    .pack(0xc, &HIGH)
    // pack `0xf` in the 8 bits specified by `MID`.
    .pack(0xf, &MID)
    // unwrap the packing value back into a `u64`.
    .bits();

assert_eq!(coffee, 0xc0ffee); // i want c0ffee

pack模块中的大多数函数都是const fn,允许在const上下文中使用打包规范。

有关详细信息,请参阅pack模块的模块级文档。

bitfield!

bitfield!宏允许声明性地定义结构化位域类型。该宏将生成使用pack模块的打包规范API来表示位域类型的代码。

例如

mycelium_bitfield::bitfield! {
    /// Bitfield types can have doc comments.
    #[derive(Eq, PartialEq)] // ...and attributes
    pub struct MyBitfield<u16> {
        /// Generates a packing spec named `HELLO` for the first 6
        /// least-significant bits.
        pub const HELLO = 6;

        // Fields with names starting with `_` can be used to mark bits as
        // reserved.
        const _RESERVED = 4;

        /// Generates a packing spec named `WORLD` for the next 3 bits.
        pub const WORLD = 3;

        /// A boolean value will generate a packing spec for a single bit.
        pub const FLAG: bool;
    }
}

// Bitfield types can be cheaply constructed from a raw numeric
// representation:
let bitfield = MyBitfield::from_bits(0b10100_0011_0101);

// `get` methods can be used to unpack fields from a bitfield type:
assert_eq!(bitfield.get(MyBitfield::HELLO), 0b11_0101);
assert_eq!(bitfield.get(MyBitfield::WORLD), 0b0101);

// `with` methods can be used to pack bits into a bitfield type by
// value:
let bitfield2 = MyBitfield::new()
    .with(MyBitfield::HELLO, 0b11_0101)
    .with(MyBitfield::WORLD, 0b0101);

assert_eq!(bitfield, bitfield2);

// `set` methods can be used to mutate a bitfield type in place:
let mut bitfield3 = MyBitfield::new();

bitfield3
    .set(MyBitfield::HELLO, 0b011_0101)
    .set(MyBitfield::WORLD, 0b0101);

assert_eq!(bitfield, bitfield3);

有关宏的使用和生成的代码的详细信息,请参阅bitfield!宏的文档。

FromBits特质

可以为用户定义的类型实现FromBits特质,这些类型可以用作bitfield!生成的结构化位域类型的子字段。此特质可以手动为任何具有定义位表示的用户定义类型实现,或者可以使用enum_from_bits!宏自动为枚举类型生成。

例如

use mycelium_bitfield::{bitfield, enum_from_bits, FromBits};

// An enum type can implement the `FromBits` trait if it has a
// `#[repr(uN)]` attribute.
#[repr(u8)]
#[derive(Debug, Eq, PartialEq)]
enum MyEnum {
    Foo = 0b00,
    Bar = 0b01,
    Baz = 0b10,
}

impl FromBits<u32> for MyEnum {
    // Two bits can represent all possible `MyEnum` values.
    const BITS: u32 = 2;
    type Error = &'static str;

    fn try_from_bits(bits: u32) -> Result<Self, Self::Error> {
        match bits as u8 {
            bits if bits == Self::Foo as u8 => Ok(Self::Foo),
            bits if bits == Self::Bar as u8 => Ok(Self::Bar),
            bits if bits == Self::Baz as u8 => Ok(Self::Baz),
            _ => Err("expected one of 0b00, 0b01, or 0b10"),
        }
    }

    fn into_bits(self) -> u32 {
        self as u8 as u32
    }
}

// Alternatively, the `enum_from_bits!` macro can be used to
// automatically generate a `FromBits` implementation for an
// enum type:
enum_from_bits! {
    #[derive(Debug, Eq, PartialEq)]
    pub enum MyGeneratedEnum<u8> {
        /// Isn't this cool?
        Wow = 0b1001,
        /// It sure is! :D
        Whoa = 0b0110,
    }
}

bitfield! {
    pub struct TypedBitfield<u32> {
        /// Use the first two bits to represent a typed `MyEnum` value.
        const ENUM_VALUE: MyEnum;

        /// Typed values and untyped raw bit fields can be used in the
        /// same bitfield type.
        pub const SOME_BITS = 6;

        /// The `FromBits` trait is also implemented for `bool`, which
        /// can be used to implement bitflags.
        pub const FLAG_1: bool;
        pub const FLAG_2: bool;

        /// `FromBits` is also implemented by (signed and unsigned) integer
        /// types. This will allow the next 8 bits to be treated as a `u8`.
        pub const A_BYTE: u8;

        /// We can also use the automatically generated enum:
        pub const OTHER_ENUM: MyGeneratedEnum;
    }
}

// Unpacking a typed value with `get` will return that value, or panic if
// the bit pattern is invalid:
let my_bitfield = TypedBitfield::from_bits(0b0010_0100_0011_0101_1001_1110);

assert_eq!(my_bitfield.get(TypedBitfield::ENUM_VALUE), MyEnum::Baz);
assert_eq!(my_bitfield.get(TypedBitfield::FLAG_1), true);
assert_eq!(my_bitfield.get(TypedBitfield::FLAG_2), false);
assert_eq!(my_bitfield.get(TypedBitfield::OTHER_ENUM), MyGeneratedEnum::Wow);

// The `try_get` method will return an error rather than panicking if an
// invalid bit pattern is encountered:

let invalid = TypedBitfield::from_bits(0b0011);

// There is no `MyEnum` variant for 0b11.
assert!(invalid.try_get(TypedBitfield::ENUM_VALUE).is_err());

请参阅FromBits特性文档以了解如何为用户定义的类型实现FromBits

无运行时依赖