1use std::fmt::{Display, Formatter, Result};
2#[cfg(feature = "operators")]
3use std::ops::{BitAnd, BitAndAssign, BitOr, BitOrAssign, BitXor, BitXorAssign, Shl, ShlAssign, Shr, ShrAssign};
4use minipaste::paste;
5
6macro_rules! create_flags {
7 ($name:ident, $vtype:tt, $n:expr) => {
8 paste! {
9 #[doc = concat!("Condenses ", stringify!($n), " booleans into a single ", stringify!($vtype), ".")]
10 #[derive(Copy, Clone, Eq, PartialEq, Debug, Default)]
11 pub struct $name($vtype);
12
13 impl $name {
14 #[doc = "Manually set all flags"]
15 #[cfg_attr(feature = "inline", inline)]
16 pub fn [<from_ $vtype>](value: $vtype) -> $name {
17 $name(value)
18 }
19
20 #[doc = "All flags are false"]
21 #[cfg_attr(feature = "inline", inline)]
22 pub fn none() -> $name {
23 $name($vtype::MIN)
24 }
25
26 #[doc = "All flags are true"]
27 #[cfg_attr(feature = "inline", inline)]
28 pub fn all() -> $name {
29 $name($vtype::MAX)
30 }
31
32 #[doc = "Get the n'th bit (flag)"]
33 #[cfg_attr(feature = "inline", inline)]
34 pub fn get(&self, index: $vtype) -> bool {
35 self.0 & (1 << (index % $n)) != 0
36 }
37
38 #[doc = "Flip the n'th bit (flag)"]
39 #[cfg_attr(feature = "inline", inline)]
40 pub fn flip(&mut self, index: $vtype) {
41 self.0 ^= 1 << (index % $n);
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: $vtype) {
47 self.0 &= !(1 << (index % $n));
48 }
49
50 #[doc = "Set the n'th bit (flag) to 1 (true)"]
51 #[cfg_attr(feature = "inline", inline)]
52 pub fn set(&mut self, index: $vtype) {
53 self.0 |= 1 << (index % $n);
54 }
55 }
56
57 impl Display for $name {
58 fn fmt(&self, f: &mut Formatter) -> Result {
59 write!(f, "0b{:0width$b}", self.0, width = size_of::<$vtype>() * 8)
60 }
61 }
62
63 #[cfg(feature = "operators")]
64 impl BitAnd for $name {
65 type Output = $name;
66
67 fn bitand(self, rhs: Self) -> Self::Output {
68 Self(self.0 & rhs.0)
69 }
70 }
71
72 #[cfg(feature = "operators")]
73 impl BitAnd<$vtype> for $name {
74 type Output = $name;
75
76 fn bitand(self, rhs: $vtype) -> Self::Output {
77 Self(self.0 & rhs)
78 }
79 }
80
81 #[cfg(feature = "operators")]
82 impl BitAndAssign for $name {
83 fn bitand_assign(&mut self, rhs: Self) {
84 self.0 &= rhs.0;
85 }
86 }
87
88 #[cfg(feature = "operators")]
89 impl BitAndAssign<$vtype> for $name {
90 fn bitand_assign(&mut self, rhs: $vtype) {
91 self.0 &= rhs;
92 }
93 }
94
95 #[cfg(feature = "operators")]
96 impl BitOr for $name {
97 type Output = $name;
98
99 fn bitor(self, rhs: Self) -> Self::Output {
100 Self(self.0 | rhs.0)
101 }
102 }
103
104 #[cfg(feature = "operators")]
105 impl BitOr<$vtype> for $name {
106 type Output = $name;
107
108 fn bitor(self, rhs: $vtype) -> Self::Output {
109 Self(self.0 | rhs)
110 }
111 }
112
113 #[cfg(feature = "operators")]
114 impl BitOrAssign for $name {
115 fn bitor_assign(&mut self, rhs: Self) {
116 self.0 |= rhs.0;
117 }
118 }
119
120 #[cfg(feature = "operators")]
121 impl BitOrAssign<$vtype> for $name {
122 fn bitor_assign(&mut self, rhs: $vtype) {
123 self.0 |= rhs;
124 }
125 }
126
127 #[cfg(feature = "operators")]
128 impl BitXor for $name {
129 type Output = $name;
130
131 fn bitxor(self, rhs: Self) -> Self::Output {
132 Self(self.0 ^ rhs.0)
133 }
134 }
135
136 #[cfg(feature = "operators")]
137 impl BitXor<$vtype> for $name {
138 type Output = $name;
139
140 fn bitxor(self, rhs: $vtype) -> Self::Output {
141 Self(self.0 ^ rhs)
142 }
143 }
144
145 #[cfg(feature = "operators")]
146 impl BitXorAssign for $name {
147 fn bitxor_assign(&mut self, rhs: Self) {
148 self.0 ^= rhs.0;
149 }
150 }
151
152 #[cfg(feature = "operators")]
153 impl BitXorAssign<$vtype> for $name {
154 fn bitxor_assign(&mut self, rhs: $vtype) {
155 self.0 ^= rhs;
156 }
157 }
158
159 #[cfg(feature = "operators")]
160 impl Shl<$vtype> for $name {
161 type Output = $name;
162
163 fn shl(self, rhs: $vtype) -> Self::Output {
164 Self(self.0 << rhs)
165 }
166 }
167
168 #[cfg(feature = "operators")]
169 impl Shr<$vtype> for $name {
170 type Output = $name;
171
172 fn shr(self, rhs: $vtype) -> Self::Output {
173 Self(self.0 >> rhs)
174 }
175 }
176
177 #[cfg(feature = "operators")]
178 impl ShlAssign<$vtype> for $name {
179 fn shl_assign(&mut self, rhs: $vtype) {
180 self.0 <<= rhs;
181 }
182 }
183
184 #[cfg(feature = "operators")]
185 impl ShrAssign<$vtype> for $name {
186 fn shr_assign(&mut self, rhs: $vtype) {
187 self.0 >>= rhs;
188 }
189 }
190 }
191 };
192}
193
194create_flags!(Flags8, u8, 8);
195create_flags!(Flags16, u16, 16);
196create_flags!(Flags32, u32, 32);
197create_flags!(Flags64, u64, 64);
198create_flags!(Flags128, u128, 128);
199#[cfg(feature = "usize")]
200create_flags!(FlagsUSize, usize, usize::MAX);
201
202#[cfg(test)]
203mod tests {
204 use super::*;
205
206 #[test]
207 fn functions() {
208 macro_rules! check_functions {
209 ($ftype:tt, $vtype:tt) => {
210 paste! {
212 assert_eq!($ftype::[<from_ $vtype>](1).0, 1);
213 assert_eq!($ftype::[<from_ $vtype>](2).0, 2);
214 assert_eq!($ftype::[<from_ $vtype>](1 | 2).0, 1 | 2);
215 }
216
217 assert_eq!($ftype::none().0, $vtype::MIN);
219 assert_eq!($ftype::all().0, $vtype::MAX);
220
221 let mut flags = $ftype::none();
223 assert_eq!(flags.get(0), false);
224 flags.flip(0);
225 assert_eq!(flags.get(0), true);
226 flags.clear(0);
227 assert_eq!(flags.get(0), false);
228 flags.set(0);
229 assert_eq!(flags.get(0), true);
230
231 println!("{} functions passed", stringify!($ftype));
232 };
233 }
234 check_functions!(Flags8, u8);
235 check_functions!(Flags16, u16);
236 check_functions!(Flags32, u32);
237 check_functions!(Flags64, u64);
238 check_functions!(Flags128, u128);
239 #[cfg(feature = "usize")]
240 check_functions!(FlagsUSize, usize);
241 }
242
243 #[test]
244 fn display() { assert_eq!(format!("{}", Flags8::none()), "0b00000000");
246 assert_eq!(format!("{}", Flags8::all()), "0b11111111");
247 println!("Flags8 display passed");
248
249 assert_eq!(format!("{}", Flags16::none()), "0b0000000000000000");
250 assert_eq!(format!("{}", Flags16::all()), "0b1111111111111111");
251 println!("Flags16 display passed");
252
253 assert_eq!(format!("{}", Flags32::none()), "0b00000000000000000000000000000000");
254 assert_eq!(format!("{}", Flags32::all()), "0b11111111111111111111111111111111");
255 println!("Flags32 display passed");
256
257 assert_eq!(format!("{}", Flags64::none()), "0b0000000000000000000000000000000000000000000000000000000000000000");
258 assert_eq!(format!("{}", Flags64::all()), "0b1111111111111111111111111111111111111111111111111111111111111111");
259 println!("Flags64 display passed");
260
261 assert_eq!(format!("{}", Flags128::none()), "0b00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000");
262 assert_eq!(format!("{}", Flags128::all()), "0b11111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111");
263 println!("Flags128 display passed");
264
265 #[cfg(feature = "usize")]
266 {
267 assert_eq!(format!("{}", FlagsUSize::none()), format!("0b{:0width$b}", usize::MIN, width = size_of::<usize>() * 8));
268 assert_eq!(format!("{}", FlagsUSize::all()), format!("0b{:0width$b}", usize::MAX, width = size_of::<usize>() * 8));
269 println!("FlagsUSize display passed");
270 }
271 }
272
273 #[test]
274 #[cfg(feature = "operators")]
275 fn bit_ops() {
276 macro_rules! check_bit_ops {
277 ($ftype:tt, $vtype:tt) => {
278 let all = $ftype::all();
279 paste! {
280 let one = $ftype::[<from_ $vtype>](1); let not_one = $ftype::[<from_ $vtype>](($vtype::MAX - 1));
282
283 let two = $ftype::[<from_ $vtype>](2); let four = $ftype::[<from_ $vtype>](4); }
286 assert_eq!(all & one, one);
287 assert_eq!(all & one.0, one);
288
289 assert_eq!(all | one, all);
290 assert_eq!(all | one.0, all);
291
292 assert_eq!(all ^ one, not_one);
293 assert_eq!(all ^ one.0, not_one);
294
295 assert_eq!(two << 1, four);
296 assert_eq!(two >> 1, one);
297
298 let mut and_assign = $ftype::all();
300 and_assign &= one;
301 assert_eq!(and_assign, one);
302
303 let mut and_assign = $ftype::all();
304 and_assign &= one.0;
305 assert_eq!(and_assign, one);
306
307 let mut or_assign = $ftype::all();
309 or_assign |= one;
310 assert_eq!(or_assign, all);
311
312 let mut or_assign = $ftype::all();
313 or_assign |= one.0;
314 assert_eq!(or_assign, all);
315
316 let mut xor_assign = $ftype::all();
318 xor_assign ^= one;
319 assert_eq!(xor_assign, not_one);
320
321 let mut xor_assign = $ftype::all();
322 xor_assign ^= one.0;
323 assert_eq!(xor_assign, not_one);
324
325 let mut shl_assign = two;
327 shl_assign <<= 1;
328 assert_eq!(shl_assign, four);
329
330 let mut shr_assign = two;
332 shr_assign >>= 1;
333 assert_eq!(shr_assign, one);
334
335 println!("{} bit ops passed", stringify!($ftype));
336 };
337 }
338 check_bit_ops!(Flags8, u8);
339 check_bit_ops!(Flags16, u16);
340 check_bit_ops!(Flags32, u32);
341 check_bit_ops!(Flags64, u64);
342 check_bit_ops!(Flags128, u128);
343 #[cfg(feature = "usize")]
344 check_bit_ops!(FlagsUSize, usize);
345 }
346}