1#[macro_export]
2macro_rules! flags {
3 ($flags:ty, $max_flags:expr, $flag_value: ty) => {
4 $crate::flags!($flags, $max_flags, $flag_value, u8);
5 };
6
7 ($flags:ty, $max_flags:expr, $flag_value: ty, $flag_index:ty) => {
8 $crate::paste::paste! {
9 #[anchor_lang::zero_copy]
11 #[derive(PartialEq, Eq)]
12 #[cfg_attr(feature = "debug", derive(Debug))]
13 #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
14 pub struct [<$flags Container>] {
15 value: $flag_value,
16 }
17
18 impl Default for [<$flags Container>] {
19 fn default() -> Self {
20 type [<$flags Map>] = $crate::bitmaps::Bitmap<$max_flags>;
21
22 Self {
23 value: [<$flags Map>]::new().into_value(),
24 }
25 }
26 }
27
28 $crate::impl_flags!($flags, $max_flags, $flag_value, $flag_index);
29 }
30 };
31}
32
33#[macro_export]
34macro_rules! impl_flags {
35 ($flags:ty, $max_flags:expr, $flag_value: ty) => {
36 $crate::impl_flags!($flags, $max_flags, $flag_value, u8);
37 };
38
39 ($flags:ty, $max_flags:expr, $flag_value: ty, $flag_index:ty) => {
40 $crate::paste::paste! {
41 type [<$flags Map>] = $crate::bitmaps::Bitmap<$max_flags>;
42 type [<$flags Value>] = $flag_value;
49 type [<$flags Index>] = $flag_index;
50
51 #[allow(dead_code)]
52 impl [<$flags Container>] {
53 fn flag_to_index(flag: $flags) -> usize {
54 usize::from( [<$flags Index>]::from(flag))
55 }
56
57 fn into_map(self) -> [<$flags Map>] {
58 [<$flags Map>]::from_value(self.value)
59 }
60
61 pub fn get_flag(&self, flag: $flags) -> bool {
63 let index = Self::flag_to_index(flag);
64 let map = self.into_map();
65 map.get(index)
66 }
67
68 pub fn set_flag(&mut self, flag: $flags, value: bool) -> bool {
70 let index = Self::flag_to_index(flag);
71 let mut map = self.into_map();
72 let previous = map.set(index, value);
73 self.value = map.into_value();
74 previous
75 }
76
77 pub fn into_value(self) -> [<$flags Value>] {
79 self.into_map().into_value()
80 }
81
82 pub fn from_value(value: [<$flags Value>]) -> Self {
84 Self {
85 value,
86 }
87 }
88 }
89 }
90 };
91}
92
93#[cfg(test)]
94mod tests {
95 use bytemuck::Zeroable;
96
97 #[derive(num_enum::IntoPrimitive)]
98 #[repr(u8)]
99 enum Flags {
100 Enabled,
101 }
102
103 #[test]
104 fn basic() {
105 flags!(Flags, 8, u8);
106
107 let mut flags = FlagsContainer::zeroed();
108 assert!(!flags.get_flag(Flags::Enabled));
109 let previous = flags.set_flag(Flags::Enabled, true);
110 assert!(!previous);
111 assert!(flags.get_flag(Flags::Enabled));
112
113 let value = flags.into_value();
114
115 assert_eq!(value, 1);
116 }
117}