use std::{
fmt::Display,
ops::{
Add, AddAssign, Div, DivAssign, Index, IndexMut, Mul, MulAssign, Sub,
SubAssign,
},
};
use super::Vec2Range;
#[derive(Debug, Copy, Clone, PartialEq, Eq, Default)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct Vec2<T = usize> {
pub x: T,
pub y: T,
}
impl<T> Vec2<T> {
pub fn new(x: T, y: T) -> Self {
Self { x, y }
}
}
impl Vec2<usize> {
pub fn saturating_sub<T>(&self, rhs: T) -> Self
where
T: Into<Self>,
{
let rhs = rhs.into();
Self {
x: self.x.saturating_sub(rhs.x),
y: self.y.saturating_sub(rhs.y),
}
}
pub fn checked_sub<T>(&self, rhs: T) -> Option<Self>
where
T: Into<Self>,
{
let rhs = rhs.into();
Some(Self {
x: self.x.checked_sub(rhs.x)?,
y: self.y.checked_sub(rhs.y)?,
})
}
}
impl<T> Vec2<T>
where
T: Copy + Into<f64>,
{
pub fn magnitude(&self) -> f64 {
let x = self.x.into();
let y = self.y.into();
(x * x + y * y).sqrt()
}
pub fn normalize(&self) -> Vec2<f64> {
let mag = self.magnitude();
Vec2::new(self.x.into() / mag, self.y.into() / mag)
}
}
impl<T> Vec2<T>
where
T: Copy,
{
pub fn transpone(&mut self) {
(self.x, self.y) = (self.y, self.x);
}
pub fn inverse(&self) -> Self {
Self {
x: self.y,
y: self.x,
}
}
}
impl<T> Vec2<T>
where
T: Copy + PartialOrd,
{
pub fn to(self, other: Vec2<T>) -> Vec2Range<T> {
Vec2Range::new(self, other)
}
}
impl<T> Index<usize> for Vec2<T> {
type Output = T;
fn index(&self, index: usize) -> &Self::Output {
match index {
0 => &self.x,
1 => &self.y,
_ => panic!("index {index} is out of bounds for Coords"),
}
}
}
impl<T> IndexMut<usize> for Vec2<T> {
fn index_mut(&mut self, index: usize) -> &mut Self::Output {
match index {
0 => &mut self.x,
1 => &mut self.y,
_ => panic!("index {index} is out of bounds for Coords"),
}
}
}
impl<T> PartialOrd for Vec2<T>
where
T: PartialOrd,
{
fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
if self.x < other.x && self.y < other.y {
Some(std::cmp::Ordering::Less)
} else if self.x > other.x && self.y > other.y {
Some(std::cmp::Ordering::Greater)
} else {
None
}
}
}
impl<T> Ord for Vec2<T>
where
T: PartialOrd + Ord,
{
fn cmp(&self, other: &Self) -> std::cmp::Ordering {
match (
self.x < other.x && self.y < other.y,
self.x > other.x && self.y > other.y,
) {
(true, false) => std::cmp::Ordering::Less,
(false, true) => std::cmp::Ordering::Greater,
_ => std::cmp::Ordering::Equal,
}
}
}
impl<L, R> Add<Vec2<R>> for Vec2<L>
where
L: Add<R>,
{
type Output = Vec2<L::Output>;
fn add(self, rhs: Vec2<R>) -> Self::Output {
Vec2::new(self.x + rhs.x, self.y + rhs.y)
}
}
impl<L, R> AddAssign<Vec2<R>> for Vec2<L>
where
L: AddAssign<R>,
{
fn add_assign(&mut self, rhs: Vec2<R>) {
self.x += rhs.x;
self.y += rhs.y;
}
}
impl<L, R> Sub<Vec2<R>> for Vec2<L>
where
L: Add<R>,
{
type Output = Vec2<L::Output>;
fn sub(self, rhs: Vec2<R>) -> Self::Output {
Vec2::new(self.x + rhs.x, self.y + rhs.y)
}
}
impl<L, R> SubAssign<Vec2<R>> for Vec2<L>
where
L: SubAssign<R>,
{
fn sub_assign(&mut self, rhs: Vec2<R>) {
self.x -= rhs.x;
self.y -= rhs.y;
}
}
impl<L, R> Mul<Vec2<R>> for Vec2<L>
where
L: Mul<R>,
{
type Output = Vec2<L::Output>;
fn mul(self, rhs: Vec2<R>) -> Self::Output {
Vec2::new(self.x * rhs.x, self.y * rhs.y)
}
}
impl<L, R> MulAssign<Vec2<R>> for Vec2<L>
where
L: MulAssign<R>,
{
fn mul_assign(&mut self, rhs: Vec2<R>) {
self.x *= rhs.x;
self.y *= rhs.y;
}
}
impl<L, R> Div<Vec2<R>> for Vec2<L>
where
L: Div<R>,
{
type Output = Vec2<L::Output>;
fn div(self, rhs: Vec2<R>) -> Self::Output {
Vec2::new(self.x / rhs.x, self.y / rhs.y)
}
}
impl<L, R> DivAssign<Vec2<R>> for Vec2<L>
where
L: DivAssign<R>,
{
fn div_assign(&mut self, rhs: Vec2<R>) {
self.x /= rhs.x;
self.y /= rhs.y;
}
}
impl<T> From<(T, T)> for Vec2<T> {
fn from((x, y): (T, T)) -> Self {
Self::new(x, y)
}
}
impl<T> From<[T; 2]> for Vec2<T> {
fn from([x, y]: [T; 2]) -> Self {
Self::new(x, y)
}
}
impl<T> Display for Vec2<T>
where
T: Display,
{
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "[{}, {}]", self.x, self.y)
}
}