1#[macro_export]
21macro_rules! sel {
22 ($name:ident) => {{
24 static SEL: std::sync::OnceLock<$crate::Sel> = std::sync::OnceLock::new();
25 *SEL.get_or_init(|| $crate::Sel::register(stringify!($name)))
26 }};
27 ($($name:ident :)+) => {{
29 static SEL: std::sync::OnceLock<$crate::Sel> = std::sync::OnceLock::new();
30 *SEL.get_or_init(|| $crate::Sel::register(concat!($(stringify!($name), ":"),+)))
31 }};
32}
33
34#[macro_export]
50macro_rules! class {
51 ($name:ident) => {{
52 static CLS: std::sync::OnceLock<$crate::Class> = std::sync::OnceLock::new();
53 *CLS.get_or_init(|| {
54 $crate::Class::get(stringify!($name)).expect(concat!(
55 "class ",
56 stringify!($name),
57 " not found"
58 ))
59 })
60 }};
61}
62
63#[macro_export]
81macro_rules! metal_enum {
82 (
83 $(#[$meta:meta])*
84 $vis:vis enum $name:ident : $repr:ty {
85 $(
86 $(#[$variant_meta:meta])*
87 $variant:ident = $value:expr
88 ),* $(,)?
89 }
90 ) => {
91 $(#[$meta])*
92 #[repr(transparent)]
93 #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Default)]
94 $vis struct $name(pub $repr);
95
96 impl $name {
97 $(
98 $(#[$variant_meta])*
99 pub const $variant: Self = Self($value);
100 )*
101
102 #[inline]
104 pub const fn raw(&self) -> $repr {
105 self.0
106 }
107
108 #[inline]
110 pub const fn from_raw(value: $repr) -> Self {
111 Self(value)
112 }
113 }
114
115 impl From<$repr> for $name {
116 #[inline]
117 fn from(value: $repr) -> Self {
118 Self(value)
119 }
120 }
121
122 impl From<$name> for $repr {
123 #[inline]
124 fn from(value: $name) -> Self {
125 value.0
126 }
127 }
128 };
129}
130
131#[macro_export]
153macro_rules! metal_options {
154 (
155 $(#[$meta:meta])*
156 $vis:vis struct $name:ident : $repr:ty {
157 $(
158 $(#[$flag_meta:meta])*
159 const $flag:ident = $value:expr;
160 )*
161 }
162 ) => {
163 $(#[$meta])*
164 #[repr(transparent)]
165 #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Default)]
166 $vis struct $name(pub $repr);
167
168 impl $name {
169 pub const NONE: Self = Self(0);
171
172 $(
173 $(#[$flag_meta])*
174 pub const $flag: Self = Self($value);
175 )*
176
177 #[inline]
179 pub const fn bits(&self) -> $repr {
180 self.0
181 }
182
183 #[inline]
185 pub const fn from_bits(bits: $repr) -> Self {
186 Self(bits)
187 }
188
189 #[inline]
191 pub const fn is_empty(&self) -> bool {
192 self.0 == 0
193 }
194
195 #[inline]
197 pub const fn contains(&self, other: Self) -> bool {
198 (self.0 & other.0) == other.0
199 }
200
201 #[inline]
203 pub const fn intersects(&self, other: Self) -> bool {
204 (self.0 & other.0) != 0
205 }
206
207 #[inline]
209 pub fn insert(&mut self, other: Self) {
210 self.0 |= other.0;
211 }
212
213 #[inline]
215 pub fn remove(&mut self, other: Self) {
216 self.0 &= !other.0;
217 }
218
219 #[inline]
221 pub fn toggle(&mut self, other: Self) {
222 self.0 ^= other.0;
223 }
224
225 #[inline]
227 pub fn set(&mut self, other: Self, value: bool) {
228 if value {
229 self.insert(other);
230 } else {
231 self.remove(other);
232 }
233 }
234 }
235
236 impl std::ops::BitOr for $name {
237 type Output = Self;
238 #[inline]
239 fn bitor(self, rhs: Self) -> Self {
240 Self(self.0 | rhs.0)
241 }
242 }
243
244 impl std::ops::BitOrAssign for $name {
245 #[inline]
246 fn bitor_assign(&mut self, rhs: Self) {
247 self.0 |= rhs.0;
248 }
249 }
250
251 impl std::ops::BitAnd for $name {
252 type Output = Self;
253 #[inline]
254 fn bitand(self, rhs: Self) -> Self {
255 Self(self.0 & rhs.0)
256 }
257 }
258
259 impl std::ops::BitAndAssign for $name {
260 #[inline]
261 fn bitand_assign(&mut self, rhs: Self) {
262 self.0 &= rhs.0;
263 }
264 }
265
266 impl std::ops::BitXor for $name {
267 type Output = Self;
268 #[inline]
269 fn bitxor(self, rhs: Self) -> Self {
270 Self(self.0 ^ rhs.0)
271 }
272 }
273
274 impl std::ops::BitXorAssign for $name {
275 #[inline]
276 fn bitxor_assign(&mut self, rhs: Self) {
277 self.0 ^= rhs.0;
278 }
279 }
280
281 impl std::ops::Not for $name {
282 type Output = Self;
283 #[inline]
284 fn not(self) -> Self {
285 Self(!self.0)
286 }
287 }
288
289 impl std::ops::Sub for $name {
290 type Output = Self;
291 #[inline]
293 fn sub(self, rhs: Self) -> Self {
294 Self(self.0 & !rhs.0)
295 }
296 }
297
298 impl std::ops::SubAssign for $name {
299 #[inline]
300 fn sub_assign(&mut self, rhs: Self) {
301 self.0 &= !rhs.0;
302 }
303 }
304
305 impl From<$repr> for $name {
306 #[inline]
307 fn from(value: $repr) -> Self {
308 Self(value)
309 }
310 }
311
312 impl From<$name> for $repr {
313 #[inline]
314 fn from(value: $name) -> Self {
315 value.0
316 }
317 }
318 };
319}
320
321#[cfg(test)]
322mod tests {
323 #[test]
324 fn test_metal_enum() {
325 metal_enum! {
326 pub enum TestEnum: u32 {
327 Zero = 0,
328 One = 1,
329 Two = 2,
330 }
331 }
332
333 assert_eq!(TestEnum::Zero.raw(), 0);
334 assert_eq!(TestEnum::One.raw(), 1);
335 assert_eq!(TestEnum::Two.raw(), 2);
336 assert_eq!(TestEnum::from_raw(1), TestEnum::One);
337 }
338
339 #[test]
340 fn test_metal_options() {
341 metal_options! {
342 pub struct TestFlags: u32 {
343 const A = 1 << 0;
344 const B = 1 << 1;
345 const C = 1 << 2;
346 }
347 }
348
349 let flags = TestFlags::A | TestFlags::B;
350 assert!(flags.contains(TestFlags::A));
351 assert!(flags.contains(TestFlags::B));
352 assert!(!flags.contains(TestFlags::C));
353 assert!(flags.intersects(TestFlags::A));
354 assert!(!flags.intersects(TestFlags::C));
355 assert_eq!(flags.bits(), 0b11);
356
357 let mut flags2 = TestFlags::NONE;
358 flags2.insert(TestFlags::C);
359 assert!(flags2.contains(TestFlags::C));
360 flags2.remove(TestFlags::C);
361 assert!(flags2.is_empty());
362 }
363}