1use core::marker::PhantomData;
2use std::collections::BTreeMap;
3
4#[cfg(feature = "serde")]
5use serde::Serialize;
6
7pub trait FiniteSet<const N: usize>: Copy + Sized {
9 const ALL: [Self; N];
10 const LEN: usize = N;
11
12 #[inline]
13 fn iter() -> impl Iterator<Item = Self> {
14 Self::ALL.into_iter()
15 }
16
17 #[inline]
18 fn iter_rev() -> impl Iterator<Item = Self> {
19 Self::ALL.into_iter().rev()
20 }
21}
22
23pub trait Empty {
24 const EMPTY: Self;
25
26 fn is_empty(&self) -> bool;
27}
28
29impl Empty for u8 {
30 const EMPTY: Self = 0;
31
32 fn is_empty(&self) -> bool {
33 *self == Self::EMPTY
34 }
35}
36
37impl Empty for u128 {
38 const EMPTY: Self = 0;
39
40 fn is_empty(&self) -> bool {
41 *self == Self::EMPTY
42 }
43}
44
45impl<T> Empty for Option<T> {
46 const EMPTY: Self = None;
47
48 fn is_empty(&self) -> bool {
49 self.is_none()
50 }
51}
52
53impl<T> Empty for Vec<T> {
54 const EMPTY: Self = Vec::new();
55
56 fn is_empty(&self) -> bool {
57 self.is_empty()
58 }
59}
60
61#[derive(Clone, Copy, Debug)]
63pub struct Table<X, T, const N: usize> {
64 pub all: [T; N],
65 __: PhantomData<X>,
66}
67
68impl<X, T, const N: usize> Table<X, T, N> {
69 #[inline]
70 pub const fn new(all: [T; N]) -> Self {
71 Self { all, __: PhantomData }
72 }
73}
74
75impl<X, T: Copy, const N: usize> Table<X, T, N> {
76 #[inline]
77 pub const fn filled(value: T) -> Self {
78 Self { all: [value; N], __: PhantomData }
79 }
80}
81
82impl<X, T: Empty, const N: usize> Empty for Table<X, T, N> {
83 const EMPTY: Self = Self::new([const { T::EMPTY }; N]);
84
85 fn is_empty(&self) -> bool {
86 self.all.iter().all(Empty::is_empty)
87 }
88}
89
90impl<X, T: Empty, const N: usize> Table<X, T, N> {
91 #[inline]
92 pub const fn empty() -> Self {
93 Self::EMPTY
94 }
95}
96
97impl<X, T: Default, const N: usize> Default for Table<X, T, N>
98where
99 [T; N]: Default,
100{
101 fn default() -> Self {
102 Self { all: Default::default(), __: PhantomData }
103 }
104}
105
106impl<X, T, const N: usize> From<Table<X, T, N>> for BTreeMap<X, T>
107where
108 T: Copy,
109 X: FiniteSet<N> + Ord,
110{
111 fn from(table: Table<X, T, N>) -> Self {
112 X::iter().zip(table.all).collect()
113 }
114}
115
116#[cfg(feature = "serde")]
117impl<X, T: Serialize, const N: usize> Serialize for Table<X, T, N>
118where
119 T: Copy + Serialize,
120 X: FiniteSet<N> + Ord + Serialize,
121{
122 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
123 where
124 S: serde::Serializer,
125 {
126 Serialize::serialize(&BTreeMap::from(*self), serializer)
127 }
128}
129
130#[macro_export]
213macro_rules! finite_set {
214 (
215 $(#[$name_meta:meta])*
216 $name:ident,
217 $(#[$table_meta:meta])*
218 $table:ident {
219 $($(#[$variant_meta:meta])* $variant:ident $(= $value:tt)? as $field:tt),+ $(,)?
220 }
221 ) => {
222 $crate::finite_set! {
223 @table
224 { $crate::finite_set!(@count $($variant),+) },
225 { $(#[$name_meta])* },
226 $name,
227 { $(#[$table_meta])* },
228 $table,
229 $table {
230 $($(#[$variant_meta])* $variant $(= $value)? as $field),+
231 }
232 }
233 };
234
235 (
236 $(#[$name_meta:meta])*
237 $name:ident,
238 $(#[$table_meta:meta])*
239 $table:ident {
240 $($(#[$variant_meta:meta])* $variant:ident $(= $value:tt)? as $field:tt),+ $(,)?
241 },
242 $cursor:ident
243 ) => {
244 $crate::finite_set! {
245 @table
246 { $crate::finite_set!(@count $($variant),+) },
247 { $(#[$name_meta])* },
248 $name,
249 { $(#[$table_meta])* },
250 $table,
251 $table {
252 $($(#[$variant_meta])* $variant $(= $value)? as $field),+
253 }
254 }
255
256 $crate::finite_set! {
257 @cursor
258 { $crate::finite_set!(@count $($variant),+) },
259 $name,
260 $cursor
261 }
262 };
263
264 (
265 $(#[$name_meta:meta])*
266 $name:ident,
267 $(#[$record_meta:meta])*
268 $record:ident,
269 $(#[$table_meta:meta])*
270 $table:ident,
271 {
272 $($(#[$variant_meta:meta])* $variant:ident $(= $value:tt)? as $field:ident),+ $(,)?
273 }
274 ) => {
275 $crate::finite_set! {
276 @record
277 { $crate::finite_set!(@count $($variant),+) },
278 { $(#[$name_meta])* },
279 $name,
280 { $(#[$record_meta])* },
281 $record,
282 { $(#[$table_meta])* },
283 $table,
284 {
285 $($(#[$variant_meta])* $variant $(= $value)? as $field),+
286 }
287 }
288 };
289
290 (
291 @table
292 $len:expr,
293 { $(#[$name_meta:meta])* },
294 $name:ident,
295 { $(#[$table_meta:meta])* },
296 $table:ident,
297 $table_expr:ident {
298 $($(#[$variant_meta:meta])* $variant:ident $(= $value:tt)? as $field:tt),+ $(,)?
299 }
300 ) => {
301 $(#[$name_meta])*
302 #[repr(u8)]
303 #[derive(Clone, Copy, Debug, Eq, Ord, PartialEq, PartialOrd)]
304 #[cfg_attr(feature = "serde", derive(SerializeDisplay))]
305 pub enum $name {
306 $(
307 $(#[$variant_meta])*
308 $variant $(= $value)?
309 ),+
310 }
311
312 $(#[$table_meta])*
313 pub type $table<T = bool> = $crate::finite::Table<$name, T, $len>;
314
315 impl $crate::finite::FiniteSet<$len> for $name {
316 const ALL: [Self; $len] = [$(Self::$variant),+];
317 }
318
319 #[doc = concat!(stringify!($name), " Finite Set API.")]
320 impl $name {
321 pub const LEN: usize = $len;
322
323 pub const ALL: [Self; $len] = <Self as $crate::finite::FiniteSet<$len>>::ALL;
324
325 #[inline]
326 pub const fn name(self) -> &'static str {
327 match self {
328 $(Self::$variant => $crate::finite_set!(@name $field)),+
329 }
330 }
331
332 #[inline]
333 pub const fn eq(self, other: Self) -> bool {
334 self as u8 == other as u8
335 }
336
337 #[inline]
338 pub const fn index(self) -> usize {
339 let mut index = 0;
340 while index < Self::ALL.len() {
341 if Self::ALL[index] as u8 == self as u8 {
342 return index;
343 }
344 index += 1;
345 }
346 unreachable!()
347 }
348
349 #[inline]
350 pub const fn from_index(index: u8) -> Option<Self> {
351 if index < Self::LEN as u8 {
352 Some(Self::panicky_from_index(index))
353 } else {
354 None
355 }
356 }
357
358 #[inline]
359 #[track_caller]
360 pub(crate) const fn panicky_from_index(index: u8) -> Self {
361 assert!(index < Self::LEN as u8);
362 Self::ALL[index as usize]
363 }
364
365 #[inline]
366 pub fn iter() -> impl Iterator<Item = Self> {
367 <Self as $crate::finite::FiniteSet<$len>>::iter()
368 }
369
370 #[inline]
371 pub fn iter_rev() -> impl Iterator<Item = Self> {
372 <Self as $crate::finite::FiniteSet<$len>>::iter_rev()
373 }
374 }
375
376 impl core::fmt::Display for $name {
377 #[inline]
378 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
379 f.write_str(self.name())
380 }
381 }
382
383 impl<T: Copy> $crate::finite::Table<$name, T, $len> {
384 #[inline]
385 pub const fn get(&self, key: $name) -> T {
386 self.all[key.index()]
387 }
388
389 #[inline]
390 pub const fn set(&mut self, key: $name, value: T) {
391 self.all[key.index()] = value;
392 }
393 }
394
395 impl<T> $crate::finite::Table<$name, T, $len> {
396 #[inline]
397 pub const fn get_ref(&self, key: $name) -> &T {
398 &self.all[key.index()]
399 }
400
401 #[inline]
402 pub const fn get_mut(&mut self, key: $name) -> &mut T {
403 &mut self.all[key.index()]
404 }
405 }
406
407 impl<T> core::ops::Index<$name> for $crate::finite::Table<$name, T, $len> {
408 type Output = T;
409
410 #[inline]
411 fn index(&self, key: $name) -> &T {
412 &self.all[key.index()]
413 }
414 }
415
416 impl<T> core::ops::IndexMut<$name> for $crate::finite::Table<$name, T, $len> {
417 #[inline]
418 fn index_mut(&mut self, key: $name) -> &mut T {
419 &mut self.all[key.index()]
420 }
421 }
422 };
423
424 (
425 @record
426 $len:expr,
427 { $(#[$name_meta:meta])* },
428 $name:ident,
429 { $(#[$record_meta:meta])* },
430 $record:ident,
431 { $(#[$table_meta:meta])* },
432 $table:ident,
433 {
434 $($(#[$variant_meta:meta])* $variant:ident $(= $value:tt)? as $field:ident),+ $(,)?
435 }
436 ) => {
437 $crate::finite_set! {
438 @table
439 $len,
440 { $(#[$name_meta])* },
441 $name,
442 { $(#[$table_meta])* },
443 $table,
444 $table {
445 $($(#[$variant_meta])* $variant $(= $value)? as $field),+
446 }
447 }
448
449 $(#[$record_meta])*
450 #[derive(Clone, Copy, Debug, Default, Eq, Ord, PartialEq, PartialOrd)]
451 pub struct $record<T = bool> {
452 $(
453 $(#[$variant_meta])*
454 pub $field: T
455 ),+
456 }
457
458 impl<T: Copy> $record<T> {
459 #[inline]
460 pub const fn get(&self, key: $name) -> T {
461 *self.get_ref(key)
462 }
463 }
464
465 impl<T> $record<T> {
466 #[inline]
467 pub const fn get_ref(&self, key: $name) -> &T {
468 match key {
469 $( $name::$variant => &self.$field ),+
470 }
471 }
472
473 #[inline]
474 pub const fn get_mut(&mut self, key: $name) -> &mut T {
475 match key {
476 $( $name::$variant => &mut self.$field ),+
477 }
478 }
479 }
480
481 impl<T: $crate::finite::Empty> $crate::finite::Empty for $record<T> {
482 const EMPTY: Self = Self {
483 $( $field: T::EMPTY ),+
484 };
485
486 fn is_empty(&self) -> bool {
487 $( self.$field.is_empty() )&&+
488 }
489 }
490
491 impl<T> core::ops::Index<$name> for $record<T> {
492 type Output = T;
493
494 #[inline]
495 fn index(&self, key: $name) -> &T {
496 self.get_ref(key)
497 }
498 }
499
500 impl<T> core::ops::IndexMut<$name> for $record<T> {
501 #[inline]
502 fn index_mut(&mut self, key: $name) -> &mut T {
503 self.get_mut(key)
504 }
505 }
506 };
507
508 (
509 @cursor
510 $len:expr,
511 $name:ident,
512 $cursor:ident
513 ) => {
514 #[derive(Clone, Copy, Debug, Eq, Ord, PartialEq, PartialOrd)]
515 pub struct $cursor {
516 next: u8,
517 }
518
519 impl $name {
520 #[inline]
521 pub const fn cursor() -> $cursor {
522 $cursor { next: 0 }
523 }
524 }
525
526 impl $cursor {
527 #[inline]
528 pub const fn next(&mut self) -> Option<$name> {
529 if self.done() {
530 None
531 } else {
532 let value = $name::panicky_from_index(self.next);
533 self.next += 1;
534 Some(value)
535 }
536 }
537
538 #[inline]
539 pub const fn skip(&mut self, n: u8) -> bool {
540 let Some(next) = self.next.checked_add(n) else {
541 return false;
542 };
543 if next > $len as u8 {
544 return false;
545 }
546 self.next = next;
547 true
548 }
549
550 #[inline]
551 pub const fn done(self) -> bool {
552 self.next >= $len as u8
553 }
554 }
555 };
556
557 (@count $($variant:ident),+) => {
558 <[()]>::len(&[$($crate::finite_set!(@unit $variant)),+])
559 };
560
561 (@unit $variant:ident) => {
562 ()
563 };
564
565 (@name $field:ident) => {
566 stringify!($field)
567 };
568
569 (@name $field:literal) => {
570 $field
571 };
572}
573
574#[macro_export]
575macro_rules! finite_for {
579 ($value:ident in $set:ty $body:block) => {{
580 let all = <$set>::ALL;
581 let mut index = 0usize;
582 while index < all.len() {
583 let $value = all[index];
584 $body
585 index += 1;
586 }
587 }};
588}
589
590