use core::fmt::{self, Write as _};
use core::str::FromStr;
use thiserror::Error;
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub enum Seat {
North,
East,
South,
West,
}
impl Seat {
pub const ALL: [Self; 4] = [Self::North, Self::East, Self::South, Self::West];
#[must_use]
pub const fn partner(self) -> Self {
match self {
Self::North => Self::South,
Self::East => Self::West,
Self::South => Self::North,
Self::West => Self::East,
}
}
#[must_use]
pub const fn lho(self) -> Self {
match self {
Self::North => Self::East,
Self::East => Self::South,
Self::South => Self::West,
Self::West => Self::North,
}
}
#[must_use]
pub const fn rho(self) -> Self {
match self {
Self::North => Self::West,
Self::East => Self::North,
Self::South => Self::East,
Self::West => Self::South,
}
}
#[must_use]
#[inline]
pub const fn letter(self) -> char {
match self {
Self::North => 'N',
Self::East => 'E',
Self::South => 'S',
Self::West => 'W',
}
}
}
const _: () = assert!(Seat::ALL[0] as u8 == 0);
const _: () = assert!(Seat::ALL[1] as u8 == 1);
const _: () = assert!(Seat::ALL[2] as u8 == 2);
const _: () = assert!(Seat::ALL[3] as u8 == 3);
impl fmt::Display for Seat {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.write_char(self.letter())
}
}
#[derive(Debug, Error, Clone, Copy, PartialEq, Eq)]
#[error("Invalid seat: expected one of N, E, S, W (or full names)")]
pub struct ParseSeatError;
impl FromStr for Seat {
type Err = ParseSeatError;
fn from_str(s: &str) -> Result<Self, Self::Err> {
match s.to_ascii_uppercase().as_str() {
"N" | "NORTH" => Ok(Self::North),
"E" | "EAST" => Ok(Self::East),
"S" | "SOUTH" => Ok(Self::South),
"W" | "WEST" => Ok(Self::West),
_ => Err(ParseSeatError),
}
}
}
bitflags::bitflags! {
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct SeatFlags: u8 {
const NORTH = 0b0001;
const EAST = 0b0010;
const SOUTH = 0b0100;
const WEST = 0b1000;
}
}
impl SeatFlags {
pub const EMPTY: Self = Self::empty();
pub const ALL: Self = Self::all();
pub const NS: Self = Self::NORTH.union(Self::SOUTH);
pub const EW: Self = Self::EAST.union(Self::WEST);
}
impl From<Seat> for SeatFlags {
fn from(seat: Seat) -> Self {
match seat {
Seat::North => Self::NORTH,
Seat::East => Self::EAST,
Seat::South => Self::SOUTH,
Seat::West => Self::WEST,
}
}
}