1use std::fmt;
2use minipaste::paste;
3
4macro_rules! create_flags {
5 ($name:ident, $vtype:tt, $n:expr) => {
6 paste! {
7 #[doc = concat!("Condenses ", stringify!($n), " booleans into a single ", stringify!($vtype), ".")]
8 #[derive(Copy, Clone, Eq, PartialEq, Debug, Default)]
9 pub struct $name($vtype);
10
11 impl $name {
12 #[doc = "Manually set all flags"]
13 #[cfg_attr(feature = "inline", inline)]
14 pub fn [<from_ $vtype>](value: $vtype) -> $name {
15 $name(value)
16 }
17
18 #[doc = "All flags are false"]
19 #[cfg_attr(feature = "inline", inline)]
20 pub fn none() -> $name {
21 $name($vtype::MIN)
22 }
23
24 #[doc = "All flags are true"]
25 #[cfg_attr(feature = "inline", inline)]
26 pub fn all() -> $name {
27 $name($vtype::MAX)
28 }
29
30 #[doc = "Get the n'th bit (flag)"]
31 #[cfg_attr(feature = "inline", inline)]
32 pub fn get(&self, index: $vtype) -> bool {
33 let index = index % $n;
34 self.0 & (1 << index) != 0
35 }
36
37 #[doc = "Flip the n'th bit (flag)"]
38 #[cfg_attr(feature = "inline", inline)]
39 pub fn flip(&mut self, index: usize) {
40 let index = index % $n;
41 self.0 ^= 1 << index;
42 }
43
44 #[doc = "Reset the n'th bit (flag) to 0 (false)"]
45 #[cfg_attr(feature = "inline", inline)]
46 pub fn clear(&mut self, index: usize) {
47 let index = index % $n;
48 self.0 &= !(1 << index);
49 }
50
51 #[doc = "Set the n'th bit (flag) to 1 (true)"]
52 #[cfg_attr(feature = "inline", inline)]
53 pub fn set(&mut self, index: usize) {
54 let index = index % $n;
55 self.0 |= 1 << index;
56 }
57 }
58
59 impl fmt::Display for $name {
60 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
61 write!(f, "0b{:0width$b}", self.0, width = size_of::<$vtype>() * 8)
62 }
63 }
64 }
65 };
66}
67
68create_flags!(Flags8, u8, 8);
69create_flags!(Flags16, u16, 16);
70create_flags!(Flags32, u32, 32);
71create_flags!(Flags64, u64, 64);
72create_flags!(Flags128, u128, 128);
73#[cfg(feature = "usize")]
74create_flags!(FlagsUSize, usize, usize::MAX);
75
76#[cfg(test)]
77mod tests {
78 use super::*;
79
80 #[test]
81 fn functions() {
82 const FLAG_0: u8 = 0b00000001;
83 const FLAG_1: u8 = 0b00000010;
84
85 assert_eq!(Flags8::from_u8(FLAG_0).0, FLAG_0);
86 assert_eq!(Flags8::from_u8(FLAG_1).0, FLAG_1);
87 assert_eq!(Flags8::from_u8(FLAG_0 | FLAG_1).0, FLAG_0 | FLAG_1);
88
89 assert_eq!(Flags8::none().0, 0b00000000);
90 assert_eq!(Flags8::all().0, 0b11111111);
91
92 let mut flags = Flags8::none();
93 assert_eq!(flags.get(0), false);
94 flags.flip(0);
95 assert_eq!(flags.get(0), true);
96 flags.clear(0);
97 assert_eq!(flags.get(0), false);
98 flags.set(0);
99 assert_eq!(flags.get(0), true);
100 }
101
102 #[test]
103 fn display() {
104 assert_eq!(format!("{}", Flags8::none()), "0b00000000");
105 assert_eq!(format!("{}", Flags8::all()), "0b11111111");
106
107 assert_eq!(format!("{}", Flags16::none()), "0b0000000000000000");
108 assert_eq!(format!("{}", Flags16::all()), "0b1111111111111111");
109
110 assert_eq!(format!("{}", Flags32::none()), "0b00000000000000000000000000000000");
111 assert_eq!(format!("{}", Flags32::all()), "0b11111111111111111111111111111111");
112
113 assert_eq!(format!("{}", Flags64::none()), "0b0000000000000000000000000000000000000000000000000000000000000000");
114 assert_eq!(format!("{}", Flags64::all()), "0b1111111111111111111111111111111111111111111111111111111111111111");
115
116 assert_eq!(format!("{}", Flags128::none()), "0b00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000");
117 assert_eq!(format!("{}", Flags128::all()), "0b11111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111");
118
119 #[cfg(feature = "usize")]
120 {
121 assert_eq!(format!("{}", FlagsUSize::none()), format!("0b{:0width$b}", usize::MIN, width = size_of::<usize>() * 8));
122 assert_eq!(format!("{}", FlagsUSize::all()), format!("0b{:0width$b}", usize::MAX, width = size_of::<usize>() * 8));
123 }
124 }
125}