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模式
7,765 每月下载量
用于 81 个crate(7个直接使用)
31KB
642 行
bitmask
枚举作用域位标志的位掩码生成器
用法
在您的 Cargo.toml
中将 bitmask
添加为依赖项
[dependency]
bitmask = "^0.5.0"
然后添加以下片段到您的crate根目录
#[macro_use]
extern crate bitmask;
特性
Bitmask支持一个特性:std
。默认启用,这将引入标准库,并为生成的类型自动派生 Hash
和 Debug
。如果您不想派生这些特性,请确保您没有启用默认特性。
示例
使用 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-64
、u8-64
、isize
、usize
)。
应用
有时您可能需要封装一些通过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);