use std::iter::{ExactSizeIterator, FusedIterator, Iterator};
use std::ops::Neg;
#[repr(u8)]
#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
#[cfg_attr(feature = "serde-1", derive(Serialize, Deserialize))]
pub enum Direction {
YZ = 0,
XZ = 1,
XY = 2,
ZY = 3,
ZX = 4,
YX = 5,
UP = 6,
DOWN = 7,
}
impl Direction {
pub fn clockwise(self) -> Direction {
use Direction as D;
match self {
D::XZ => D::ZY,
D::XY => D::ZX,
D::ZY => D::YX,
D::ZX => D::YZ,
D::YX => D::XZ,
D::YZ => D::XY,
D::UP => D::UP,
D::DOWN => D::DOWN,
}
}
pub fn counter_clockwise(self) -> Direction {
use Direction as D;
match self {
D::XZ => D::YX,
D::XY => D::YZ,
D::ZY => D::XZ,
D::ZX => D::XY,
D::YX => D::ZY,
D::YZ => D::ZX,
D::UP => D::UP,
D::DOWN => D::DOWN,
}
}
pub fn iter() -> Directions {
Directions(0)
}
pub fn iter_planar() -> PlanarDirections {
PlanarDirections(0)
}
}
impl Neg for Direction {
type Output = Self;
fn neg(self) -> Direction {
use Direction as D;
match self {
D::YZ => D::ZY,
D::XZ => D::ZX,
D::XY => D::YX,
D::ZY => D::YZ,
D::ZX => D::XZ,
D::YX => D::XY,
D::UP => D::DOWN,
D::DOWN => D::UP,
}
}
}
#[derive(Debug)]
pub struct NotDirection;
impl std::convert::TryFrom<u8> for Direction {
type Error = NotDirection;
fn try_from(num: u8) -> Result<Self, NotDirection> {
if num < 8 {
Ok(unsafe { std::mem::transmute(num as u8) })
} else {
Err(NotDirection)
}
}
}
#[derive(Debug)]
pub struct Directions(usize);
impl Iterator for Directions {
type Item = Direction;
fn next(&mut self) -> Option<Direction> {
if self.0 < 8 {
let result = unsafe { std::mem::transmute(self.0 as u8) };
self.0 += 1;
Some(result)
} else {
None
}
}
fn size_hint(&self) -> (usize, Option<usize>) {
(8 - self.0, Some(8 - self.0))
}
}
impl FusedIterator for Directions {}
impl ExactSizeIterator for Directions {}
#[derive(Debug)]
pub struct PlanarDirections(usize);
impl Iterator for PlanarDirections {
type Item = Direction;
fn next(&mut self) -> Option<Direction> {
if self.0 < 6 {
let result = unsafe { std::mem::transmute(self.0 as u8) };
self.0 += 1;
Some(result)
} else {
None
}
}
fn size_hint(&self) -> (usize, Option<usize>) {
(8 - self.0, Some(6 - self.0))
}
}
impl FusedIterator for PlanarDirections {}
impl ExactSizeIterator for PlanarDirections {}
#[cfg(feature = "rand-07")]
mod distribution_impl {
use super::Direction;
use std::convert::TryFrom;
use rand::distributions::{Distribution, Standard};
use rand::Rng;
#[derive(Copy, Clone, Debug, Default)]
pub struct Planar;
impl Distribution<Direction> for Planar {
fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> Direction {
Direction::try_from(rng.gen_range(0, 6))
.expect("rng should return number in range 0..6")
}
}
impl Distribution<Direction> for Standard {
fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> Direction {
Direction::try_from(rng.gen_range(0, 8))
.expect("rng should return number in range 0..8")
}
}
}
#[cfg(feature = "rand-07")]
#[doc(inline)]
pub use distribution_impl::Planar;
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn can_iter() {
use Direction as D;
assert_eq!(
vec![D::YZ, D::XZ, D::XY, D::ZY, D::ZX, D::YX, D::UP, D::DOWN,],
Direction::iter().collect::<Vec<_>>(),
);
}
#[test]
fn can_iter_planar() {
use Direction as D;
assert_eq!(
vec![D::YZ, D::XZ, D::XY, D::ZY, D::ZX, D::YX,],
Direction::iter_planar().collect::<Vec<_>>(),
);
}
}