#bit-flags #enums #scoped #generator #default #automatic #cargo

no-std bitmask

枚举作用域位标志的位掩码生成器

6个版本 (破坏性更新)

使用旧的Rust 2015

0.5.0 2019年3月18日
0.4.0 2017年5月7日
0.3.0 2017年1月31日
0.2.0 2017年1月22日
0.1.1 2017年1月21日

#1195 in Rust模式

Download history 1347/week @ 2024-03-14 2072/week @ 2024-03-21 1360/week @ 2024-03-28 1629/week @ 2024-04-04 1741/week @ 2024-04-11 1406/week @ 2024-04-18 2428/week @ 2024-04-25 1459/week @ 2024-05-02 1685/week @ 2024-05-09 1813/week @ 2024-05-16 2111/week @ 2024-05-23 2427/week @ 2024-05-30 1815/week @ 2024-06-06 1698/week @ 2024-06-13 1618/week @ 2024-06-20 2057/week @ 2024-06-27

7,765 每月下载量
用于 81 个crate(7个直接使用)

MIT/Apache

31KB
642

bitmask

枚举作用域位标志的位掩码生成器

文档

用法

在您的 Cargo.toml 中将 bitmask 添加为依赖项

[dependency]
bitmask = "^0.5.0"

然后添加以下片段到您的crate根目录

#[macro_use]
extern crate bitmask;

特性

Bitmask支持一个特性:std。默认启用,这将引入标准库,并为生成的类型自动派生 HashDebug。如果您不想派生这些特性,请确保您没有启用默认特性。

示例

使用 cargo run --example <name> 运行特定的示例。

类似crate


lib.rs:

枚举作用域位标志的位掩码生成器。

bitmask! 宏创建一个结构体和一个枚举,该枚举包含您的标志。枚举包含所有位标志变体,而结构体是这些位标志的混合,称为位掩码。其语法如下

bitmask! {
    pub mask <struct_name>: <struct_type> where flags <enum_name> {
        <flag_name> = <value>,
        ...
    }
}

其中 pub 是可选的,struct_type 可以是原始整数类型之一(i8-64u8-64isizeusize)。

应用

有时您可能需要封装一些通过FFI公开许多定义为常量的库,例如C或其他代码。让我们看看这个示例模块

mod tex {
    ...
    pub const TEXTURE_2D: u32   = 1;
    pub const TEXTURE_3D: u32   = 2;
    pub const FLIP: u32         = 4;
    ...
    pub fn set_options(mask: u32) { ... }
}

为了避免冲突,您可以通过mod作用域像这样使用它们

tex::set_options(tex::TEXTURE_2D | tex::FLIP);

但这并不能保证您不会使用无效的标志值。例如,您可能做

set_options(3 | 8);

现在想象一下,你有一个枚举来存储所有这些标志,还有一个不接受除枚举变体和自身之外的任何类型的通用类型。这正是 bitmask! 为你做的!它会根据你提供的变体(标志)生成一个枚举,并创建一个包含这些变体的掩码的struct。所以,我们的例子现在看起来是这样的

bitmask! {
    pub mask TexMask: u32 where flags TexOption {
        Texture2d = tex::TEXTURE_2D,
        Texture3d = tex::TEXTURE_3D,
        Flip = tex::FLIP
    }
}

fn set_options(mask: TexMask) {
    tex::set_options(*mask);
}

// Single flag
set_options(TexOption::Texture2d.into());
set_options(TexMask::from(TexOption::Texture3d));

// Multiple flags
set_options(TexOption::Texture2d | TexOption::Flip);

那些可以做到但会随时间而改变的事情

如果你出于某种原因想自己定义枚举和struct,你可以这样做,并使用宏的 @IMPL 分支来实现方法。唯一的限制是,你的struct的内部字段必须命名为 mask,枚举的大小应该与struct相同,可以通过使用与 mask 字段相同的整型类型的 #[repr()] 修饰符来实现。

如果你想使用预实现的掩码方法,为你的自定义类型实现 Into<struct_name>Deref 是可能的,但这不适用于像 BitOr 这样的特质实现。

示例

bitmask! {
    mask BitMask: u32 where flags Flags {
        Flag1       = 0x00000001,
        Flag2       = 0x000000F0,
        Flag3       = 0x00000800,
        Flag123     = 0x000008F1,
        // Note that function calls like `isize::min_value()`
        // can't be used for enum discriminants in Rust.
        FlagMax     = ::std::u32::MAX
    }
}

let mut mask = BitMask::none();

mask.set(Flags::Flag1 | Flags::Flag2);
assert_eq!(*mask, 0x000000F1);

mask.unset(Flags::Flag1);
assert_eq!(*mask, 0x000000F0);

mask.set(Flags::Flag123);
assert_eq!(*mask, 0x000008F1);

你可以为宏的每个元素添加元属性,如文档(#[doc = "..."])。

bitmask! {
    /// Doc comment for the struct
    pub mask SomeOtherMask: isize where
    /// Doc comment for the enum
    flags SomeOtherFlags {
        /// Doc comment for the flag
        FlagZero    = 0,
        FlagOne     = 1
    }
}

也许不是最好的例子,但仍然是...蛋糕是爱!

bitmask! {
    mask Cake: u8 where flags Ingredients {
        Sugar   = 0b00000001,
        Eggs    = 0b00000010,
        Flour   = 0b00000100,
        Milk    = 0b00001000
    }
}

let quality_cake = Cake::all();
assert_eq!(*quality_cake, 0b00001111);

无运行时依赖

特性