use std::fmt::{Debug, Formatter}; use std::marker::PhantomData; use std::ops::Sub; pub trait CoordinateSpace {} #[derive(PartialEq, Eq, Clone, Copy, PartialOrd, Ord)] pub struct Coordinates, S: CoordinateSpace> { pub x: T, pub y: T, space: PhantomData, } impl + Debug + PartialOrd, S: CoordinateSpace> Debug for Coordinates { fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { f.debug_tuple("@") .field(&self.x) .field(&self.y) .finish() } } pub trait CoordLimits: PartialOrd + PartialEq { type Data: Sized + PartialOrd + PartialEq; const MIN: Self::Data; const MAX: Self::Data; } impl CoordLimits for u8 { type Data = u8; const MIN: u8 = 0; const MAX: u8 = 255; } impl CoordLimits for u16 { type Data = u16; const MIN: u16 = u16::MIN; const MAX: u16 = u16::MAX; } impl CoordLimits for usize { type Data = usize; const MIN: usize = usize::MIN; const MAX: usize = usize::MAX; } impl, S: CoordinateSpace> Coordinates { pub const fn new(x: T, y: T) -> Self { Self { x, y, space: PhantomData, } } fn top_left() -> Self { Self::new(T::MIN, T::MIN) } fn top_right() -> Self { Self::new(T::MAX, T::MIN) } fn bottom_left() -> Self { Self::new(T::MIN, T::MAX) } fn bottom_right() -> Self { Self::new(T::MAX, T::MAX) } } #[derive(PartialEq, Debug, Copy, Clone)] pub struct Virtual {} impl CoordinateSpace for Virtual {} #[derive(PartialEq, Debug, Copy, Clone)] pub struct Physical {} impl CoordinateSpace for Physical {} #[derive(PartialEq, Debug, Copy, Clone)] pub struct Coord8 { x: u8, y: u8, space: PhantomData } pub type VirtualCoordinates = Coordinates; pub type PhysicalCoordinates = Coordinates; #[derive(PartialEq, Eq, Copy, Clone, Debug, PartialOrd)] pub struct Rectangle + Clone + Copy, Space: CoordinateSpace> { pub top_left: Coordinates, pub bottom_right: Coordinates } impl + Sub + Clone + Copy, Space: CoordinateSpace> Rectangle { pub fn new(top_left: Coordinates, bottom_right: Coordinates) -> Self { debug_assert!(top_left.x <= bottom_right.x); debug_assert!(top_left.y <= bottom_right.y); Self { top_left, bottom_right } } pub fn everything() -> Self { Self { top_left: Coordinates::::top_left(), bottom_right: Coordinates::::bottom_right() } } pub fn width(&self) -> CoordData { self.bottom_right.x.clone() - self.top_left.x.clone() } pub fn height(&self) -> CoordData { self.bottom_right.y.clone() - self.top_left.y.clone() } pub const fn left(&self) -> CoordData { self.top_left.x } pub const fn top(&self) -> CoordData { self.top_left.y } pub const fn right (&self) -> CoordData { self.bottom_right.x } pub const fn bottom(&self) -> CoordData { self.bottom_right.y } }