1 个不稳定版本
0.1.0 | 2024年6月23日 |
---|
#599 in 数据结构
15KB
213 行
byteflags
byteflags
实现了一个类似 bitflags 的结构,使用一个完整的字节而不是一个位来表示每个字段。这允许用户在保持位标志结构易用性的同时,在结构中编码额外的信息。
用法
将以下内容添加到您的 Cargo.toml
[dependencies]
byteflags = "0.1.0"
并将以下内容添加到您的源代码
use byteflags::*;
示例
生成一个标志结构
use byteflags::*;
byteflags! {
/// The structure definition contains a set of named flags
struct MyFlags {
A = "Flag A",
B = "Flag B",
C = "Flag C",
D = "Flag D",
}
}
fn main() {
/// The resulting structure can be used similarly to bitflags
/// Constant values
assert_eq!(
MyFlags::A,
MyFlags { A: 1, B: 0, C: 0, D: 0 }
);
/// Union
assert_eq!(
(MyFlags::A.union(MyFlags::B)),
MyFlags { A: 1, B: 1, C: 0, D: 0 }
);
/// Difference
assert_eq!(
(MyFlags { A: 0, B: 1, C: 1, D: 1} - MyFlags {A: 0, B: 1, C: 0, D: 1 }),
MyFlags { A: 0, B: 0, C: 1, D: 0}
);
/// Because each flag is a u8, you can do some arithmetic as well, including but not limited to:
/// Addition
assert_eq!(
MyFlags::A + MyFlags::A + MyFlags::B,
MyFlags { A: 2, B: 1, C: 0, D: 0 }
);
/// Multiplication by u8
assert_eq!(
(MyFlags { A: 2, B: 1, C: 0, D: 0 } * 3),
MyFlags { A: 6, B: 3, C: 0, D: 0 }
);
/// Division by u8
assert_eq!(
(MyFlags { A: 60, B: 15, C: 0, D: 0 } / 3),
MyFlags { A: 20, B: 5, C: 0, D: 0 }
);
/// Multiplication by other byteflag struct
assert_eq!(
(MyFlags { A: 1, B: 2, C: 3, D: 4 } * MyFlags { A: 0, B: 1, C: 2, D: 3 }),
MyFlags { A: 0, B: 2, C: 6, D: 12 }
);
/// Subtractive Assignment
let mut flags = MyFlags { A: 2, B: 2, C: 1, D: 0, };
flags -= MyFlags::C;
assert_eq!(
flags,
MyFlags { A: 2, B: 2, C: 0, D: 0 }
);
/// There are a couple other bells and whistles, such as:
/// Conversion and serialization
let flags = MyFlags { A: 0, B: 1, C: 10, D: 100 };
assert_eq!(flags.to_vec(), vec![0, 1, 10, 100]);
assert_eq!(serde_json::to_string(&flags).unwrap(), "[0,1,10,100]".to_string());
assert_eq!(flags, serde_json::from_str::<MyFlags>("[0,1,10,100]").unwrap());
/// contains() and match
let d = MyFlags::D;
assert_eq!(
match d {
MyFlags::A => "No",
MyFlags::B => "Nope",
MyFlags::C => "Wrong",
MyFlags::D => "This one!",
_ => "",
},
"This one!"
);
let flags = MyFlags { A: 0, B: 1, C: 10, D: 100 };
assert!(flags.contains(&MyFlags::B));
assert!(!flags.contains(&MyFlags::A));
/// Display with labels
assert_eq!(
format!("{}", MyFlags::A),
"Flag A"
);
assert_eq!(
format!("{}", MyFlags::A + MyFlags::B),
"Flag A + Flag B"
);
/// Access a flag via index
assert_eq!(
MyFlags::ALL_CONSTS[2],
MyFlags::C
);
/// Get random flag with the "rand" feature
/// Probabilities are weighted according to the flag value
let weights = MyFlags{ A: 255, B: 127, C: 0, D: 0};
let random_value = weights.get_random();
// 66% chance of being MyFlags::A, 33% chance of being MyFlags::B
}
有争议的设计选择
这些设计选择可能不会立即明显。如果您需要不同的行为,请随时提交一个 pull request。
use byteflags::*;
byteflags! {
struct MyFlags {
A = "Flag A",
B = "Flag B",
}
}
fn main() {
/// All arithmetic is saturating
assert_eq!(
(MyFlags{ A: 200, B: 0 } + MyFlags{ A: 200, B: 0 }),
MyFlags{ A: u8::MAX, B: 0 }
);
assert_eq!(
(MyFlags::A - (MyFlags::A + MyFlags::A)),
MyFlags::empty()
);
assert_eq!(
(MyFlags{ A: 128, B: 1 } * 128),
MyFlags{ A: u8::MAX, B: 128 }
);
/// contains() only checks if a value is nonzero
assert_eq!(
(MyFlags::A).contains(&MyFlags{ A: 100, B: 0 }),
true
);
/// Display also only checks if a value is nonzero
assert_eq!(
format!("{}", MyFlags{ A: 5, B: 10 }),
"Flag A + Flag B"
);
/// all() gives values of 1
assert_eq!(
MyFlags::all(),
MyFlags{ A: 1, B: 1 }
);
}
依赖项
~0.7–1.7MB
~37K SLoC