1#[macro_export]
2macro_rules! flags {
3 ($flagset_type:ty: $($flag:expr),* $(,)?) => {{
4 let mut flagset = <$flagset_type>::default();
5 $(
6 <$flagset_type as $crate::flags::FlagSet<_>>::set(&mut flagset, $flag);
7 )*
8 flagset
9 }};
10}
11
12#[macro_export]
13macro_rules! flagset {
14 ($name:ident: $first:ty $(, $rest:ty)* $(,)?) => {
15 #[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
16 pub struct $name {
17 flags: $crate::flags::Flags<{ tightbeam::flagset!(@count $first $(, $rest)*) }>,
18 }
19
20 impl Default for $name {
21 fn default() -> Self {
22 Self {
23 flags: $crate::flags::Flags::default(),
24 }
25 }
26 }
27
28 impl From<$name> for $crate::flags::Flags<{ tightbeam::flagset!(@count $first $(, $rest)*) }> {
29 fn from(flagset: $name) -> $crate::flags::Flags<{ tightbeam::flagset!(@count $first $(, $rest)*) }> {
30 flagset.flags
31 }
32 }
33
34 impl From<Vec<u8>> for $name {
35 fn from(bytes: Vec<u8>) -> Self {
36 Self {
37 flags: $crate::flags::Flags::from(bytes.as_slice()),
38 }
39 }
40 }
41
42 impl From<&[u8]> for $name {
43 fn from(bytes: &[u8]) -> Self {
44 Self {
45 flags: $crate::flags::Flags::from(bytes),
46 }
47 }
48 }
49
50 impl From<Option<Vec<u8>>> for $name {
51 fn from(bytes: Option<Vec<u8>>) -> Self {
52 match bytes {
53 Some(bytes) => Self::from(bytes),
54 None => Self::default(),
55 }
56 }
57 }
58
59 impl $name {
60 fn get_pos(type_name: &str) -> usize {
61 tightbeam::flagset!(@position_lookup type_name, 0, $first $(, $rest)*)
62 }
63 }
64
65 impl<T> $crate::flags::FlagSet<T> for $name
66 where
67 T: Into<u8> + PartialEq<u8> + Default + 'static,
68 {
69 fn set(&mut self, flag: T)
70 where
71 T: Into<u8> + 'static,
72 {
73 let type_name = std::any::type_name::<T>();
74 let type_name = ::core::any::type_name::<T>();
75 let pos = Self::get_pos(type_name);
76 self.flags.set_at(pos, flag.into());
77 }
78
79 fn unset(&mut self) {
80 let type_name = std::any::type_name::<T>();
81 let type_name = ::core::any::type_name::<T>();
82 let pos = Self::get_pos(type_name);
83 self.flags.set_at(pos, T::default().into());
84 }
85
86 fn contains(&self, flag: T) -> bool
87 where
88 T: Into<u8> + PartialEq<u8> + Default + 'static,
89 {
90 let type_name = std::any::type_name::<T>();
91 let type_name = ::core::any::type_name::<T>();
92 let pos = Self::get_pos(type_name);
93 let stored_value = self.flags.get_at(pos);
94 let flag_value = flag.into();
95
96 if stored_value == flag_value {
99 true
100 } else if stored_value == 0 {
101 flag_value == T::default().into()
102 } else {
103 false
104 }
105 }
106 }
107
108 impl From<$name> for Vec<u8> {
109 fn from(flagset: $name) -> Vec<u8> {
110 Vec::from(flagset.flags)
111 }
112 }
113
114 impl From<$name> for $crate::matrix::Matrix<{ tightbeam::flagset!(@count $first $(, $rest)*) }> {
115 fn from(flagset: $name) -> Self {
116 Self::from(flagset.flags)
117 }
118 }
119
120 impl From<&$name> for $crate::matrix::Matrix<{ tightbeam::flagset!(@count $first $(, $rest)*) }> {
121 fn from(flagset: &$name) -> Self {
122 Self::from(&flagset.flags)
123 }
124 }
125
126 impl From<$crate::matrix::MatrixDyn> for $name {
128 fn from(m: $crate::matrix::MatrixDyn) -> Self {
129 let n = m.n();
130 let dim = ::core::cmp::min(n as usize, tightbeam::flagset!(@count $first $(, $rest)*));
131 let mut flags = $crate::flags::Flags::<{ tightbeam::flagset!(@count $first $(, $rest)*) }>::default();
132 for __idx in 0..dim {
133 flags.set_at(__idx, m.get(__idx as u8, __idx as u8));
134 }
135 Self { flags }
136 }
137 }
138
139 impl From<&$crate::matrix::MatrixDyn> for $name {
140 fn from(m: &$crate::matrix::MatrixDyn) -> Self {
141 let n = m.n();
142 let dim = ::core::cmp::min(n as usize, tightbeam::flagset!(@count $first $(, $rest)*));
143 let mut flags = $crate::flags::Flags::<{ tightbeam::flagset!(@count $first $(, $rest)*) }>::default();
144 for __idx in 0..dim {
145 flags.set_at(__idx, m.get(__idx as u8, __idx as u8));
146 }
147 Self { flags }
148 }
149 }
150
151 impl From<$crate::matrix::Matrix<{ tightbeam::flagset!(@count $first $(, $rest)*) }>> for $name {
153 fn from(m: $crate::matrix::Matrix<{ tightbeam::flagset!(@count $first $(, $rest)*) }>) -> Self {
154 let mut flags = $crate::flags::Flags::<{ tightbeam::flagset!(@count $first $(, $rest)*) }>::default();
155 for __idx in 0..(tightbeam::flagset!(@count $first $(, $rest)*) as usize) {
156 flags.set_at(__idx, m.get(__idx as u8, __idx as u8));
157 }
158 Self { flags }
159 }
160 }
161
162 impl From<&$crate::matrix::Matrix<{ tightbeam::flagset!(@count $first $(, $rest)*) }>> for $name {
163 fn from(m: &$crate::matrix::Matrix<{ tightbeam::flagset!(@count $first $(, $rest)*) }>) -> Self {
164 let mut flags = $crate::flags::Flags::<{ tightbeam::flagset!(@count $first $(, $rest)*) }>::default();
165 for __idx in 0..(tightbeam::flagset!(@count $first $(, $rest)*) as usize) {
166 flags.set_at(__idx, m.get(__idx as u8, __idx as u8));
167 }
168 Self { flags }
169 }
170 }
171
172 impl $crate::matrix::MatrixLike for $name {
174 fn n(&self) -> u8 {
175 tightbeam::flagset!(@count $first $(, $rest)*) as u8
176 }
177
178 fn get(&self, r: u8, c: u8) -> u8 {
179 self.flags.get(r, c)
180 }
181
182 fn set(&mut self, r: u8, c: u8, value: u8) {
183 self.flags.set(r, c, value);
184 }
185
186 fn fill(&mut self, value: u8) {
187 self.flags.fill(value);
188 }
189 }
190
191 impl TryFrom<$name> for $crate::matrix::MatrixDyn {
193 type Error = $crate::matrix::MatrixError;
194
195 fn try_from(flagset: $name) -> Result<Self, Self::Error> {
196 $crate::matrix::MatrixDyn::try_from(flagset.flags)
197 }
198 }
199
200 impl TryFrom<&$name> for $crate::matrix::MatrixDyn {
201 type Error = $crate::matrix::MatrixError;
202
203 fn try_from(flagset: &$name) -> Result<Self, Self::Error> {
204 $crate::matrix::MatrixDyn::try_from(&flagset.flags)
205 }
206 }
207 };
208
209 (@count $first:ty) => { 1 };
210 (@count $first:ty, $($rest:ty),*) => { 1 + tightbeam::flagset!(@count $($rest),*) };
211
212 (@impl_methods $pos:ident = $pos_val:expr, $first:ty) => {
213 tightbeam::flagset!(@method_for_type $pos_val, $first);
214 };
215
216 (@impl_methods $pos:ident = $pos_val:expr, $first:ty, $($rest:ty),*) => {
217 tightbeam::flagset!(@method_for_type $pos_val, $first);
218 tightbeam::flagset!(@impl_methods $pos = $pos_val + 1, $($rest),*);
219 };
220
221 (@position_lookup $type_name:expr, $pos:expr, $ty:ty) => {
222 if $type_name.ends_with(stringify!($ty)) { $pos } else { usize::MAX }
223 };
224
225 (@position_lookup $type_name:expr, $pos:expr, $ty:ty, $($rest:ty),*) => {
226 if $type_name.ends_with(stringify!($ty)) {
227 $pos
228 } else {
229 tightbeam::flagset!(@position_lookup $type_name, $pos + 1, $($rest),*)
230 }
231 };
232}