Skip to main content

bool_flags/
lib.rs

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}