macro_rules! enumeration {
($(#[$outer:meta])* $vis:vis $name:ident, [$($var:ident),+ $(,)?]) => {
$(#[$outer])*
#[derive(Copy, Debug, Eq)]
#[derive_const(Clone, PartialEq, Ord, PartialOrd)]
#[must_use]
#[repr(u8)]
$vis enum $name {
$(#[allow(missing_docs)] $var = ${index()}),+
}
#[allow(dead_code)]
impl $name {
$vis const COUNT: usize = ${count(var)};
$vis const VARIANTS: [$name; Self::COUNT] = [
$(Self::$var,)+
];
$vis const NAMES: [&'static str; Self::COUNT] = [
$(stringify!($var),)+
];
#[inline]
#[allow(unsafe_code)]
pub(crate) const unsafe fn from_u8_unchecked(repr: u8) -> Self {
debug_assert!(Self::from_u8(repr).is_some());
std::mem::transmute(repr)
}
#[inline]
#[must_use]
pub(crate) const fn from_u8(repr: u8) -> Option<Self> {
Self::VARIANTS.get(repr as usize).copied()
}
#[inline]
#[must_use]
$vis fn iter() -> std::array::IntoIter<Self, ${count(var)}> {
Self::VARIANTS.into_iter()
}
#[inline]
#[must_use]
$vis fn name(self) -> &'static str {
Self::NAMES[self.as_usize()]
}
#[inline]
#[must_use]
pub(crate) const fn as_u8(self) -> u8 {
self as u8
}
#[inline]
#[must_use]
pub(crate) const fn as_usize(self) -> usize {
self as _
}
}
impl const From<$name> for u8 {
#[inline]
#[must_use]
fn from(this: $name) -> Self {
this as _
}
}
impl const From<$name> for usize {
#[inline]
#[must_use]
fn from(this: $name) -> Self {
this as usize
}
}
impl<T> const std::ops::Index<$name> for [T; $name::COUNT] {
type Output = T;
fn index(&self, val: $name) -> &Self::Output {
self.index(val.as_usize())
}
}
impl<T> std::ops::IndexMut<$name> for [T; $name::COUNT] {
fn index_mut(&mut self, val: $name) -> &mut Self::Output {
self.index_mut(val.as_usize())
}
}
#[cfg(test)]
mod tests_enumerate_macro {
use super::*;
#[test]
fn test_impl() {
for v1 in $name::iter() {
assert_eq!(v1.clone(), v1);
assert_eq!(v1.name(), format!("{:?}", v1));
for v2 in $name::iter() {
assert_eq!(
v1.partial_cmp(&v2).unwrap(),
v1.cmp(&v2)
);
}
}
}
#[test]
fn test_impl_from() {
for (repr, variant) in $name::iter().enumerate() {
assert_eq!(repr as u8, u8 ::from(variant));
assert_eq!(repr, usize::from(variant));
}
}
#[test]
fn test_from_u8() {
for (repr, variant) in $name::iter().enumerate() {
assert_eq!(variant, unsafe_optimization!{
$name::from_u8(repr as _).unwrap(),
$name::from_u8_unchecked(repr as _)
})
}
}
}
}
}
mod board;
mod castling;
mod color;
mod direction;
mod file;
mod piece;
mod rank;
mod ruleset;
mod square;
mod token;
pub use board::Board;
pub use castling::{CastlingVariety, CastlingPath, CastlingRights, CastlingSide};
pub use color::Color;
pub use direction::Direction;
pub use file::File;
pub use piece::Piece;
pub use rank::Rank;
pub use ruleset::Ruleset;
pub use square::Square;
pub use token::Token;