use std::{
fmt::Debug,
ops::{Add, AddAssign, Sub, SubAssign},
};
pub struct Xy<T> {
pub x: T,
pub y: T,
}
impl<T> Xy<T> {
#[inline]
pub const fn new(x: T, y: T) -> Self {
Self { x, y }
}
}
impl<T: Copy> Xy<T> {
#[inline]
pub const fn swapped(&self) -> Self {
Self {
x: self.y,
y: self.x,
}
}
}
impl<T: Clone> Clone for Xy<T> {
fn clone(&self) -> Self {
Self {
x: self.x.clone(),
y: self.y.clone(),
}
}
}
impl<T: Copy> Copy for Xy<T> {}
impl<T: Debug> Debug for Xy<T> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("Xy").field("x", &self.x).field("y", &self.y).finish()
}
}
impl<T: Default> Default for Xy<T> {
fn default() -> Self {
Self {
x: T::default(),
y: T::default(),
}
}
}
impl<T: Eq> Eq for Xy<T> {}
impl<T: PartialEq> PartialEq for Xy<T> {
fn eq(&self, other: &Self) -> bool {
self.x == other.x && self.y == other.y
}
}
impl <T: Add<Output = T>> Add<Xy<T>> for Xy<T> {
type Output = Xy<T>;
fn add(self, rhs: Xy<T>) -> Self::Output {
Self {
x: self.x + rhs.x,
y: self.y + rhs.y,
}
}
}
impl<T: AddAssign> AddAssign<Xy<T>> for Xy<T> {
fn add_assign(&mut self, rhs: Xy<T>) {
self.x += rhs.x;
self.y += rhs.y;
}
}
impl <T: Sub<Output = T>> Sub<Xy<T>> for Xy<T> {
type Output = Xy<T>;
fn sub(self, rhs: Xy<T>) -> Self::Output {
Self {
x: self.x - rhs.x,
y: self.y - rhs.y,
}
}
}
impl<T: SubAssign> SubAssign<Xy<T>> for Xy<T> {
fn sub_assign(&mut self, rhs: Xy<T>) {
self.x -= rhs.x;
self.y -= rhs.y;
}
}
impl Xy<f32> {
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn assert_implementations() {
let u32xy_a: Xy<u32> = Xy::new(1, 3);
let u32xy_b: Xy<u32> = Xy::new(3, 1);
assert_eq!(u32xy_a, u32xy_a.clone());
assert_ne!(u32xy_a, u32xy_b);
}
#[test]
fn simple_use_case() {
type Position = Xy<u16>;
trait PositionImpl {
fn custom_x_getter(&self) -> u16;
}
impl PositionImpl for Position {
fn custom_x_getter(&self) -> u16 {
self.x
}
}
let pos_a = Position::new(1, 2);
assert_eq!(pos_a.custom_x_getter(), 1);
}
}