gardiz/
direc.rs

1//! Utilities related to directions in the plane.
2
3use crate::axis::Axis;
4use std::{
5    ops::{Index, IndexMut, Not},
6    slice,
7};
8
9/// Basic direction in a plane.
10#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
11#[cfg_attr(
12    feature = "impl-serde",
13    derive(serde::Serialize, serde::Deserialize)
14)]
15pub enum Direction {
16    /// Direction up (towards negative Y).
17    Up,
18    /// Direction down (towards positive Y).
19    Down,
20    /// Direction left (towards negative X).
21    Left,
22    /// Direction right (towards positive X).
23    Right,
24}
25
26impl Direction {
27    /// List of all possible directions. Please note that this requires no
28    /// heap-allocation and is very cheap.
29    pub const ALL: [Direction; 4] =
30        [Direction::Up, Direction::Down, Direction::Left, Direction::Right];
31
32    /// Iterator over all directions.
33    ///
34    /// # Examples
35    ///
36    /// Note that these examples put the directions in a vector, but if you want
37    /// an array of directions, just use [`Direction::ALL`].
38    ///
39    /// ## Default Order
40    /// ```rust
41    /// use gardiz::direc::{self, Direction};
42    ///
43    /// # fn main() {
44    /// let direcs: Vec<Direction> = Direction::iter().collect();
45    /// assert_eq!(
46    ///     vec![Direction::Up, Direction::Down, Direction::Left, Direction::Right],
47    ///     direcs
48    /// );
49    /// # }
50    /// ```
51    ///
52    /// ## Reverse Order
53    /// ```rust
54    /// use gardiz::direc::{self, Direction};
55    ///
56    /// # fn main() {
57    /// let direcs: Vec<Direction> = Direction::iter().rev().collect();
58    /// assert_eq!(
59    ///     vec![Direction::Right, Direction::Left, Direction::Down, Direction::Up],
60    ///     direcs
61    /// );
62    /// # }
63    /// ```
64    pub fn iter() -> Iter {
65        Iter { inner: Self::ALL.iter() }
66    }
67
68    /// Creates a direction from the given axis in the positive direction (i.e.
69    /// `X -> Right` and `Y -> Down`).
70    pub fn from_axis_pos(axis: Axis) -> Self {
71        match axis {
72            Axis::X => Direction::Right,
73            Axis::Y => Direction::Down,
74        }
75    }
76
77    /// Creates a direction from the given axis in the negative direction (i.e.
78    /// `X -> Left` and `Y -> Up`).
79    pub fn from_axis_neg(axis: Axis) -> Self {
80        match axis {
81            Axis::X => Direction::Left,
82            Axis::Y => Direction::Up,
83        }
84    }
85
86    /// Axis on which the direciton varies.
87    pub fn axis(self) -> Axis {
88        match self {
89            Direction::Up | Direction::Down => Axis::Y,
90            Direction::Left | Direction::Right => Axis::X,
91        }
92    }
93
94    /// Rotates the direction clockwise.
95    pub fn rotate_clockwise(self) -> Self {
96        match self {
97            Direction::Down => Direction::Left,
98            Direction::Left => Direction::Up,
99            Direction::Up => Direction::Right,
100            Direction::Right => Direction::Down,
101        }
102    }
103
104    /// Rotates the direction counter-clockwise.
105    pub fn rotate_countercw(self) -> Self {
106        match self {
107            Direction::Left => Direction::Down,
108            Direction::Down => Direction::Right,
109            Direction::Right => Direction::Up,
110            Direction::Up => Direction::Left,
111        }
112    }
113}
114
115impl Not for Direction {
116    type Output = Direction;
117
118    fn not(self) -> Self::Output {
119        match self {
120            Direction::Up => Direction::Down,
121            Direction::Down => Direction::Up,
122            Direction::Left => Direction::Right,
123            Direction::Right => Direction::Left,
124        }
125    }
126}
127
128/// Iterator over all "straight" 2D directions. See [`Direction::iter`].
129#[derive(Debug, Clone)]
130pub struct Iter {
131    inner: slice::Iter<'static, Direction>,
132}
133
134impl Iterator for Iter {
135    type Item = Direction;
136
137    fn next(&mut self) -> Option<Self::Item> {
138        self.inner.next().copied()
139    }
140
141    fn size_hint(&self) -> (usize, Option<usize>) {
142        self.inner.size_hint()
143    }
144}
145
146impl DoubleEndedIterator for Iter {
147    fn next_back(&mut self) -> Option<Self::Item> {
148        self.inner.next_back().copied()
149    }
150}
151
152impl ExactSizeIterator for Iter {}
153
154/// A vector written as a magnitude and a direction.
155#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
156#[cfg_attr(
157    feature = "impl-serde",
158    derive(serde::Serialize, serde::Deserialize)
159)]
160pub struct DirecVector<T> {
161    /// Mangitude, should be numeric.
162    pub magnitude: T,
163    /// Direction of the vector.
164    pub direction: Direction,
165}
166
167/// A mapping from all directions to the given data.
168#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
169#[cfg_attr(
170    feature = "impl-serde",
171    derive(serde::Serialize, serde::Deserialize)
172)]
173pub struct DirecMap<T> {
174    /// Data associated with `Direction::Up`.
175    pub up: T,
176    /// Data associated with `Direction::Left`.
177    pub left: T,
178    /// Data associated with `Direction::Down`.
179    pub down: T,
180    /// Data associated with `Direction::Right`.
181    pub right: T,
182}
183
184impl<T> DirecMap<T> {
185    /// Creates a mapping from a function.
186    pub fn from_direcs<F>(mut map: F) -> Self
187    where
188        F: FnMut(Direction) -> T,
189    {
190        Self {
191            up: map(Direction::Up),
192            left: map(Direction::Left),
193            down: map(Direction::Down),
194            right: map(Direction::Right),
195        }
196    }
197}
198
199impl<T> Index<Direction> for DirecMap<T> {
200    type Output = T;
201
202    fn index(&self, index: Direction) -> &Self::Output {
203        match index {
204            Direction::Up => &self.up,
205            Direction::Left => &self.left,
206            Direction::Down => &self.down,
207            Direction::Right => &self.right,
208        }
209    }
210}
211
212impl<T> IndexMut<Direction> for DirecMap<T> {
213    fn index_mut(&mut self, index: Direction) -> &mut Self::Output {
214        match index {
215            Direction::Up => &mut self.up,
216            Direction::Left => &mut self.left,
217            Direction::Down => &mut self.down,
218            Direction::Right => &mut self.right,
219        }
220    }
221}