Skip to main content

tightbeam/macros/
flags.rs

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 the flag matches what's stored, return true
97				// If nothing is stored (0), compare against the default value
98				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		// MatrixDyn -> FlagSet (read diagonal; ignore off-diagonals; clamp to min(n, N))
127		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		// Matrix<N> -> FlagSet (exact size; read diagonal)
152		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		// Add MatrixLike implementation
173		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		// Add TryFrom for MatrixDyn
192		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}