1use std::fmt;
9
10pub trait Directional: Copy + Sized + std::fmt::Debug + 'static {
18 type Flipped: Directional;
22
23 type Reversed: Directional;
27
28 #[must_use = "method does not modify self but returns a new value"]
30 fn flipped(self) -> Self::Flipped;
31
32 #[must_use = "method does not modify self but returns a new value"]
34 fn reversed(self) -> Self::Reversed;
35
36 #[must_use = "method does not modify self but returns a new value"]
38 fn as_direction(self) -> Direction;
39
40 #[inline]
42 fn is_vertical(self) -> bool {
43 ((self.as_direction() as u32) & 1) == 1
44 }
45
46 #[inline]
48 fn is_horizontal(self) -> bool {
49 ((self.as_direction() as u32) & 1) == 0
50 }
51
52 #[inline]
54 fn is_reversed(self) -> bool {
55 ((self.as_direction() as u32) & 2) == 2
56 }
57}
58
59macro_rules! fixed {
60 ($d:ident, $df:ident, $dr:ident) => {
61 #[derive(Copy, Clone, Default, Debug)]
63 #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
64 pub struct $d;
65 impl Directional for $d {
66 type Flipped = $df;
67 type Reversed = $dr;
68 #[inline]
69 fn flipped(self) -> Self::Flipped {
70 $df
71 }
72 #[inline]
73 fn reversed(self) -> Self::Reversed {
74 $dr
75 }
76 #[inline]
77 fn as_direction(self) -> Direction {
78 Direction::$d
79 }
80 }
81 };
82}
83fixed!(Left, Up, Right);
84fixed!(Right, Down, Left);
85fixed!(Up, Left, Down);
86fixed!(Down, Right, Up);
87
88#[crate::impl_default(Direction::Right)]
94#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Ord, PartialOrd)]
95#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
96pub enum Direction {
97 Right = 0,
98 Down = 1,
99 Left = 2,
100 Up = 3,
101}
102
103impl fmt::Display for Direction {
104 fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
105 write!(f, "{}", match self {
106 Direction::Right => "Right",
107 Direction::Down => "Down",
108 Direction::Left => "Left",
109 Direction::Up => "Up",
110 })
111 }
112}
113
114impl Directional for Direction {
115 type Flipped = Self;
116 type Reversed = Self;
117
118 fn flipped(self) -> Self::Flipped {
119 use Direction::*;
120 match self {
121 Right => Down,
122 Down => Right,
123 Left => Up,
124 Up => Left,
125 }
126 }
127
128 fn reversed(self) -> Self::Reversed {
129 use Direction::*;
130 match self {
131 Right => Left,
132 Down => Up,
133 Left => Right,
134 Up => Down,
135 }
136 }
137
138 #[inline]
139 fn as_direction(self) -> Direction {
140 self
141 }
142}
143
144bitflags! {
145 pub struct Directions: u8 {
147 const LEFT = 0b0001;
148 const RIGHT = 0b0010;
149 const UP = 0b0100;
150 const DOWN = 0b1000;
151 }
152}
153
154#[cfg(feature = "accesskit")]
155impl From<Direction> for accesskit::Orientation {
156 #[inline]
157 fn from(dir: Direction) -> Self {
158 match dir {
159 Direction::Right | Direction::Left => accesskit::Orientation::Horizontal,
160 Direction::Down | Direction::Up => accesskit::Orientation::Vertical,
161 }
162 }
163}
164
165#[cfg(test)]
166mod test {
167 use super::*;
168 use std::mem::size_of;
169
170 #[test]
171 fn size() {
172 assert_eq!(size_of::<Left>(), 0);
173 assert_eq!(size_of::<Right>(), 0);
174 assert_eq!(size_of::<Up>(), 0);
175 assert_eq!(size_of::<Down>(), 0);
176 assert_eq!(size_of::<Direction>(), 1);
177 }
178}