1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138
//! Axis-aligned directions: horizontal or vertical.
use std::fmt::Display;
use array_map::{ArrayMap, Indexable};
use serde::{Deserialize, Serialize};
/// An enumeration of axis-aligned directions.
#[derive(Debug, Clone, Copy, Serialize, Deserialize, Hash, PartialEq, Eq)]
#[repr(u8)]
#[derive(Indexable)]
pub enum Dir {
/// The horizontal, or x-aligned, direction.
Horiz,
/// The vertical, or y-aligned, direction.
Vert,
}
impl Dir {
/// Returns the other direction.
///
/// # Example
///
/// ```
/// # use geometry::prelude::*;
/// assert_eq!(Dir::Vert.other(), Dir::Horiz);
/// assert_eq!(Dir::Horiz.other(), Dir::Vert);
/// ```
pub const fn other(&self) -> Self {
match *self {
Self::Horiz => Self::Vert,
Self::Vert => Self::Horiz,
}
}
}
impl Display for Dir {
/// Displays the direction in a human-readable format.
///
/// Currently, [`Dir::Horiz`] becomes `horizontal`;
/// [`Dir::Vert`] becomes `vertical`.
/// However, users should not rely on these particular strings.
///
/// # Example
///
/// ```
/// # use geometry::prelude::*;
/// assert_eq!(format!("{}", Dir::Horiz), "horizontal");
/// assert_eq!(format!("{}", Dir::Vert), "vertical");
/// ```
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match *self {
Self::Horiz => write!(f, "horizontal"),
Self::Vert => write!(f, "vertical"),
}
}
}
impl std::ops::Not for Dir {
type Output = Self;
/// Returns the other direction.
///
/// # Example
///
/// ```
/// # use geometry::prelude::*;
/// assert_eq!(!Dir::Vert, Dir::Horiz);
/// assert_eq!(!Dir::Horiz, Dir::Vert);
/// ```
fn not(self) -> Self::Output {
self.other()
}
}
/// An association of a value with type `T` to each of the two [`Dir`]s.
#[derive(Default, Debug, Clone, Copy, Eq, PartialEq)]
pub struct Dirs<T> {
inner: ArrayMap<Dir, T, 2>,
}
impl<T> Dirs<T>
where
T: Clone,
{
/// Creates a new [`Dirs`] with `value` associated with all directions.
///
/// The value will be cloned for each [`Dir`].
///
/// If your value is [`Copy`], consider using [`Dirs::uniform`] instead.
pub fn uniform_cloned(value: T) -> Self {
Self {
inner: ArrayMap::from_value(value),
}
}
}
impl<T> Dirs<T>
where
T: Copy,
{
/// Creates a new [`Dir`] with `value` associated with all directions.
pub const fn uniform(value: T) -> Self {
Self {
inner: ArrayMap::new([value; 2]),
}
}
}
impl<T> Dirs<T> {
/// Creates a new [`Dir`] with with the provided values for each direction.
pub const fn new(horiz: T, vert: T) -> Self {
// IMPORTANT: the ordering of array elements here must match
// the ordering of variants in the [`Dir`] enum.
Self {
inner: ArrayMap::new([horiz, vert]),
}
}
/// Maps a function over the provided [`Dir`], returning a new [`Dir`].
pub fn map<B>(self, f: impl FnMut(&Dir, T) -> B) -> Dirs<B> {
Dirs {
inner: self.inner.map(f),
}
}
}
impl<T> std::ops::Index<Dir> for Dirs<T> {
type Output = T;
fn index(&self, index: Dir) -> &Self::Output {
self.inner.index(index)
}
}
impl<T> std::ops::IndexMut<Dir> for Dirs<T> {
fn index_mut(&mut self, index: Dir) -> &mut Self::Output {
self.inner.index_mut(index)
}
}