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
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
//! The sides of an axis-aligned rectangle.

use crate::dir::Dir;
use crate::sign::Sign;
use array_map::{ArrayMap, Indexable};
use serde::{Deserialize, Serialize};

/// An enumeration of the sides of an axis-aligned rectangle.
#[derive(Debug, Clone, Copy, Serialize, Deserialize, Hash, PartialEq, Eq)]
#[repr(u8)]
#[derive(Indexable)]
pub enum Side {
    /// The left side.
    Left,
    /// The bottom side.
    Bot,
    /// The right side.
    Right,
    /// The top side.
    Top,
}

impl Side {
    /// Gets the direction of the coordinate corresponding to this side.
    ///
    /// Top and bottom edges are y-coordinates, so they are on the **vertical** axis.
    /// Left and right edges are x-coordinates, so they are on the **horizontal** axis.
    ///
    /// Also see [`Side::edge_dir`].
    pub fn coord_dir(&self) -> Dir {
        use Dir::*;
        use Side::*;
        match self {
            Top | Bot => Vert,
            Left | Right => Horiz,
        }
    }

    /// Gets the direction of the edge corresponding to this side.
    ///
    /// Top and bottom edges are **horizontal** line segments;
    /// left and right edges are **vertical** line segments.
    ///
    /// Also see [`Side::coord_dir`].
    pub fn edge_dir(&self) -> Dir {
        use Dir::*;
        use Side::*;
        match self {
            Top | Bot => Horiz,
            Left | Right => Vert,
        }
    }

    /// Returns the opposite direction.
    pub fn other(&self) -> Self {
        match self {
            Side::Top => Side::Bot,
            Side::Right => Side::Left,
            Side::Bot => Side::Top,
            Side::Left => Side::Right,
        }
    }

    /// Returns the sign corresponding to moving towards this side.
    pub fn sign(&self) -> Sign {
        use Side::*;
        use Sign::*;
        match self {
            Top | Right => Pos,
            Bot | Left => Neg,
        }
    }

    /// Returns the side corresponding with the given [`Dir`] and [`Sign`].
    ///
    /// # Example
    ///
    /// ```
    /// # use geometry::prelude::*;
    /// assert_eq!(Side::with_dir_and_sign(Dir::Horiz, Sign::Neg), Side::Left);
    /// assert_eq!(Side::with_dir_and_sign(Dir::Vert, Sign::Neg), Side::Bot);
    /// assert_eq!(Side::with_dir_and_sign(Dir::Horiz, Sign::Pos), Side::Right);
    /// assert_eq!(Side::with_dir_and_sign(Dir::Vert, Sign::Pos), Side::Top);
    /// ```
    pub fn with_dir_and_sign(dir: Dir, sign: Sign) -> Side {
        match dir {
            Dir::Horiz => match sign {
                Sign::Pos => Side::Right,
                Sign::Neg => Side::Left,
            },
            Dir::Vert => match sign {
                Sign::Pos => Side::Top,
                Sign::Neg => Side::Bot,
            },
        }
    }

    /// Returns sides that bound the given direction.
    ///
    /// Users should not rely upon the order of the sides returned.
    ///
    /// # Example
    ///
    /// ```
    /// # use geometry::prelude::*;
    /// assert_eq!(Side::with_dir(Dir::Horiz), [Side::Left, Side::Right]);
    /// assert_eq!(Side::with_dir(Dir::Vert), [Side::Bot, Side::Top]);
    /// ```
    pub fn with_dir(dir: Dir) -> [Side; 2] {
        match dir {
            Dir::Horiz => [Side::Left, Side::Right],
            Dir::Vert => [Side::Bot, Side::Top],
        }
    }
}

impl std::ops::Not for Side {
    type Output = Self;
    /// Exclamation Operator returns the opposite direction
    fn not(self) -> Self::Output {
        self.other()
    }
}
/// An association of a value with type `T` to each of the four [`Side`]s.
#[derive(Default, Debug, Clone, Copy, Eq, PartialEq)]
pub struct Sides<T> {
    inner: ArrayMap<Side, T, 4>,
}

impl<T> Sides<T>
where
    T: Clone,
{
    /// Creates a new [`Sides`] with `value` associated with all sides.
    ///
    /// The value will be cloned for each [`Side`].
    ///
    /// If your value is [`Copy`], consider using [`Sides::uniform`] instead.
    pub fn uniform_cloned(value: T) -> Self {
        Self {
            inner: ArrayMap::from_value(value),
        }
    }
}

impl<T> Sides<T>
where
    T: Copy,
{
    /// Creates a new [`Sides`] with `value` associated with all sides.
    pub const fn uniform(value: T) -> Self {
        Self {
            inner: ArrayMap::new([value; 4]),
        }
    }
}

impl<T> Sides<T> {
    /// Creates a new [`Sides`] with with the provided values for each side.
    pub const fn new(left: T, bot: T, right: T, top: T) -> Self {
        // IMPORTANT: the ordering of array elements here must match
        // the ordering of variants in the [`Side`] enum.
        Self {
            inner: ArrayMap::new([left, bot, right, top]),
        }
    }

    /// Maps a function over the provided [`Sides`], returning a new [`Sides`].
    pub fn map<B>(self, f: impl FnMut(&Side, T) -> B) -> Sides<B> {
        Sides {
            inner: self.inner.map(f),
        }
    }
}

impl<T> std::ops::Index<Side> for Sides<T> {
    type Output = T;
    fn index(&self, index: Side) -> &Self::Output {
        self.inner.index(index)
    }
}

impl<T> std::ops::IndexMut<Side> for Sides<T> {
    fn index_mut(&mut self, index: Side) -> &mut Self::Output {
        self.inner.index_mut(index)
    }
}