use crate::Vec2;
use crate::XY;
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
pub enum Orientation {
Horizontal,
Vertical,
}
impl std::str::FromStr for Orientation {
type Err = ();
fn from_str(s: &str) -> Result<Self, Self::Err> {
Ok(match s {
"Vertical" | "vertical" => Self::Vertical,
"Horizontal" | "horizontal" => Self::Horizontal,
_ => return Err(()),
})
}
}
impl Orientation {
pub const fn pair() -> XY<Orientation> {
XY::new(Orientation::Horizontal, Orientation::Vertical)
}
pub fn get<T: Clone>(self, v: &XY<T>) -> T {
v.get(self).clone()
}
#[must_use]
pub const fn swap(self) -> Self {
match self {
Orientation::Horizontal => Orientation::Vertical,
Orientation::Vertical => Orientation::Horizontal,
}
}
pub fn get_mut<T>(self, v: &mut XY<T>) -> &mut T {
match self {
Orientation::Horizontal => &mut v.x,
Orientation::Vertical => &mut v.y,
}
}
#[deprecated]
pub fn get_ref<T>(self, v: &mut XY<T>) -> &mut T {
self.get_mut(v)
}
pub fn stack<T: Iterator<Item = Vec2>>(self, iter: T) -> Vec2 {
match self {
Orientation::Horizontal => iter.fold(Vec2::zero(), |a, b| a.stack_horizontal(&b)),
Orientation::Vertical => iter.fold(Vec2::zero(), |a, b| a.stack_vertical(&b)),
}
}
pub const fn make_vec(self, main_axis: usize, second_axis: usize) -> Vec2 {
Vec2::from_major_minor(self, main_axis, second_axis)
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum Direction {
Abs(Absolute),
Rel(Relative),
}
impl std::str::FromStr for Direction {
type Err = ();
fn from_str(s: &str) -> Result<Self, Self::Err> {
s.parse()
.map(Direction::Abs)
.or_else(|_| s.parse().map(Direction::Rel))
}
}
impl Direction {
pub const fn relative(self, orientation: Orientation) -> Option<Relative> {
match self {
Direction::Abs(abs) => abs.relative(orientation),
Direction::Rel(rel) => Some(rel),
}
}
pub const fn absolute(self, orientation: Orientation) -> Absolute {
match self {
Direction::Abs(abs) => abs,
Direction::Rel(rel) => rel.absolute(orientation),
}
}
#[must_use]
pub const fn opposite(self) -> Self {
match self {
Direction::Abs(abs) => Direction::Abs(abs.opposite()),
Direction::Rel(rel) => Direction::Rel(rel.swap()),
}
}
pub const fn back() -> Self {
Direction::Rel(Relative::Back)
}
pub const fn front() -> Self {
Direction::Rel(Relative::Front)
}
pub const fn left() -> Self {
Direction::Abs(Absolute::Left)
}
pub const fn right() -> Self {
Direction::Abs(Absolute::Right)
}
pub const fn up() -> Self {
Direction::Abs(Absolute::Up)
}
pub const fn down() -> Self {
Direction::Abs(Absolute::Down)
}
pub const fn none() -> Self {
Direction::Abs(Absolute::None)
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum Relative {
Front,
Back,
}
impl std::str::FromStr for Relative {
type Err = ();
fn from_str(s: &str) -> Result<Self, Self::Err> {
Ok(match s {
"Front" | "front" => Self::Front,
"Back" | "back" => Self::Back,
_ => return Err(()),
})
}
}
impl Relative {
pub const fn absolute(self, orientation: Orientation) -> Absolute {
match (orientation, self) {
(Orientation::Horizontal, Relative::Front) => Absolute::Left,
(Orientation::Horizontal, Relative::Back) => Absolute::Right,
(Orientation::Vertical, Relative::Front) => Absolute::Up,
(Orientation::Vertical, Relative::Back) => Absolute::Down,
}
}
pub fn pick<T>(self, (front, back): (T, T)) -> T {
match self {
Relative::Front => front,
Relative::Back => back,
}
}
#[must_use]
pub const fn swap(self) -> Self {
match self {
Relative::Front => Relative::Back,
Relative::Back => Relative::Front,
}
}
pub const fn a_to_b(a: usize, b: usize) -> Option<Self> {
match (a < b, a == b) {
(_, true) => None,
(true, false) => Some(Relative::Front),
(false, false) => Some(Relative::Back),
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum Absolute {
Left,
Up,
Right,
Down,
None,
}
impl std::str::FromStr for Absolute {
type Err = ();
fn from_str(s: &str) -> Result<Self, Self::Err> {
Ok(match s {
"Left" | "left" => Self::Left,
"Up" | "up" => Self::Up,
"Right" | "right" => Self::Right,
"Down" | "down" => Self::Down,
"None" | "none" => Self::None,
_ => return Err(()),
})
}
}
impl Absolute {
pub const fn relative(self, orientation: Orientation) -> Option<Relative> {
match (orientation, self) {
(Orientation::Horizontal, Absolute::Left) | (Orientation::Vertical, Absolute::Up) => {
Some(Relative::Front)
}
(Orientation::Horizontal, Absolute::Right)
| (Orientation::Vertical, Absolute::Down) => Some(Relative::Back),
_ => None,
}
}
#[must_use]
pub const fn opposite(self) -> Self {
match self {
Absolute::Left => Absolute::Right,
Absolute::Right => Absolute::Left,
Absolute::Up => Absolute::Down,
Absolute::Down => Absolute::Up,
Absolute::None => Absolute::None,
}
}
pub const fn split(self) -> (Orientation, Relative) {
match self {
Absolute::Left => (Orientation::Horizontal, Relative::Front),
Absolute::Right => (Orientation::Horizontal, Relative::Back),
Absolute::Up => (Orientation::Vertical, Relative::Front),
Absolute::Down => (Orientation::Vertical, Relative::Back),
Absolute::None => panic!("None direction not supported here"),
}
}
}