use std::fmt;
pub trait Directional: Copy + Sized + std::fmt::Debug + 'static {
type Flipped: Directional;
type Reversed: Directional;
#[must_use = "method does not modify self but returns a new value"]
fn flipped(self) -> Self::Flipped;
#[must_use = "method does not modify self but returns a new value"]
fn reversed(self) -> Self::Reversed;
#[must_use = "method does not modify self but returns a new value"]
fn as_direction(self) -> Direction;
#[inline]
fn is_vertical(self) -> bool {
((self.as_direction() as u32) & 1) == 1
}
#[inline]
fn is_horizontal(self) -> bool {
((self.as_direction() as u32) & 1) == 0
}
#[inline]
fn is_reversed(self) -> bool {
((self.as_direction() as u32) & 2) == 2
}
}
macro_rules! fixed {
($d:ident, $df:ident, $dr:ident) => {
#[derive(Copy, Clone, Default, Debug)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct $d;
impl Directional for $d {
type Flipped = $df;
type Reversed = $dr;
#[inline]
fn flipped(self) -> Self::Flipped {
$df
}
#[inline]
fn reversed(self) -> Self::Reversed {
$dr
}
#[inline]
fn as_direction(self) -> Direction {
Direction::$d
}
}
};
}
fixed!(Left, Up, Right);
fixed!(Right, Down, Left);
fixed!(Up, Left, Down);
fixed!(Down, Right, Up);
#[crate::impl_default(Direction::Right)]
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Ord, PartialOrd)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub enum Direction {
Right = 0,
Down = 1,
Left = 2,
Up = 3,
}
impl fmt::Display for Direction {
fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
write!(f, "{}", match self {
Direction::Right => "Right",
Direction::Down => "Down",
Direction::Left => "Left",
Direction::Up => "Up",
})
}
}
impl Directional for Direction {
type Flipped = Self;
type Reversed = Self;
fn flipped(self) -> Self::Flipped {
use Direction::*;
match self {
Right => Down,
Down => Right,
Left => Up,
Up => Left,
}
}
fn reversed(self) -> Self::Reversed {
use Direction::*;
match self {
Right => Left,
Down => Up,
Left => Right,
Up => Down,
}
}
#[inline]
fn as_direction(self) -> Direction {
self
}
}
#[cfg(feature = "accesskit")]
impl From<Direction> for accesskit::Orientation {
#[inline]
fn from(dir: Direction) -> Self {
match dir {
Direction::Right | Direction::Left => accesskit::Orientation::Horizontal,
Direction::Down | Direction::Up => accesskit::Orientation::Vertical,
}
}
}
#[cfg(test)]
mod test {
use super::*;
use std::mem::size_of;
#[test]
fn size() {
assert_eq!(size_of::<Left>(), 0);
assert_eq!(size_of::<Right>(), 0);
assert_eq!(size_of::<Up>(), 0);
assert_eq!(size_of::<Down>(), 0);
assert_eq!(size_of::<Direction>(), 1);
}
}