#![cfg_attr(docsrs, feature(doc_auto_cfg))]
#![cfg_attr(not(feature = "std"), no_std)]
mod interop {
#[cfg(feature = "approx_v05")]
mod approx_v05;
}
use core::{
num::TryFromIntError,
ops::{Add, AddAssign, Div, DivAssign, Mul, MulAssign, Neg, Sub, SubAssign},
};
pub type Vec2 = Vector2<f32>;
pub type IVec2 = Vector2<i32>;
pub type UVec2 = Vector2<usize>;
#[allow(clippy::exhaustive_structs)]
#[derive(Debug, Copy, Clone, Default, Eq, PartialEq, Hash)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct Vector2<T> {
#[allow(missing_docs)]
pub x: T,
#[allow(missing_docs)]
pub y: T,
}
impl Vector2<f32> {
#[allow(missing_docs)]
pub const ZERO: Self = Self::new(0., 0.);
#[allow(missing_docs)]
pub const X: Self = Self::new(1., 0.);
#[allow(missing_docs)]
pub const Y: Self = Self::new(0., 1.);
#[must_use]
#[allow(clippy::cast_possible_truncation)]
pub fn as_i32(self) -> Vector2<i32> {
Vector2 {
x: self.x as i32,
y: self.y as i32,
}
}
#[must_use]
#[doc(alias = "length")]
#[cfg(any(feature = "std", feature = "libm"))]
pub fn magnitude(self) -> f32 {
sqrt(self.magnitude_squared())
}
#[must_use]
#[cfg(any(feature = "std", feature = "libm"))]
pub fn normalize(self) -> Option<Self> {
let recip = self.magnitude().recip();
if recip.is_finite() {
Some(self * recip)
} else {
None
}
}
}
impl Vector2<i32> {
#[allow(missing_docs)]
pub const ZERO: Self = Self::new(0, 0);
#[allow(missing_docs)]
pub const X: Self = Self::new(1, 0);
#[allow(missing_docs)]
pub const Y: Self = Self::new(0, 1);
#[must_use]
#[allow(clippy::cast_precision_loss)]
pub fn as_f32(self) -> Vector2<f32> {
Vector2 {
x: self.x as f32,
y: self.y as f32,
}
}
}
impl TryFrom<Vector2<i32>> for Vector2<usize> {
type Error = TryFromIntError;
fn try_from(Vector2 { x, y }: Vector2<i32>) -> Result<Self, Self::Error> {
Ok(Self {
x: x.try_into()?,
y: y.try_into()?,
})
}
}
impl TryFrom<Vector2<usize>> for Vector2<i32> {
type Error = TryFromIntError;
fn try_from(Vector2 { x, y }: Vector2<usize>) -> Result<Self, Self::Error> {
Ok(Self {
x: x.try_into()?,
y: y.try_into()?,
})
}
}
impl<T> Vector2<T> {
#[allow(missing_docs)]
pub const fn new(x: T, y: T) -> Self {
Self { x, y }
}
}
impl<T: Copy> Vector2<T> {
pub const fn splat(value: T) -> Self {
Self { x: value, y: value }
}
}
impl<T> From<[T; 2]> for Vector2<T> {
fn from([x, y]: [T; 2]) -> Self {
Self { x, y }
}
}
impl<T> From<Vector2<T>> for [T; 2] {
fn from(Vector2 { x, y }: Vector2<T>) -> Self {
[x, y]
}
}
impl<T> From<(T, T)> for Vector2<T> {
fn from((x, y): (T, T)) -> Self {
Self { x, y }
}
}
impl<T> From<Vector2<T>> for (T, T) {
fn from(Vector2 { x, y }: Vector2<T>) -> Self {
(x, y)
}
}
impl<A> Vector2<A> {
pub fn dot<B>(self, other: Vector2<B>) -> <<A as Mul<B>>::Output as Add>::Output
where
A: Mul<B>,
<A as Mul<B>>::Output: Add,
{
(self.x * other.x) + (self.y * other.y)
}
pub fn magnitude_squared(self) -> <<A as Mul>::Output as Add>::Output
where
A: Copy + Mul,
<A as Mul>::Output: Add,
{
self.dot(self)
}
}
impl<A, B> AddAssign<Vector2<B>> for Vector2<A>
where
A: AddAssign<B>,
{
fn add_assign(&mut self, rhs: Vector2<B>) {
self.x += rhs.x;
self.y += rhs.y;
}
}
impl<A, B> Add<Vector2<B>> for Vector2<A>
where
A: Add<B>,
{
type Output = Vector2<A::Output>;
fn add(self, rhs: Vector2<B>) -> Self::Output {
Vector2 {
x: self.x + rhs.x,
y: self.y + rhs.y,
}
}
}
impl<A, B> SubAssign<Vector2<B>> for Vector2<A>
where
A: SubAssign<B>,
{
fn sub_assign(&mut self, rhs: Vector2<B>) {
self.x -= rhs.x;
self.y -= rhs.y;
}
}
impl<A, B> Sub<Vector2<B>> for Vector2<A>
where
A: Sub<B>,
{
type Output = Vector2<A::Output>;
fn sub(self, rhs: Vector2<B>) -> Self::Output {
Vector2 {
x: self.x - rhs.x,
y: self.y - rhs.y,
}
}
}
impl<A, B> MulAssign<B> for Vector2<A>
where
A: MulAssign<B>,
B: Copy,
{
fn mul_assign(&mut self, rhs: B) {
self.x *= rhs;
self.y *= rhs;
}
}
impl<A, B> Mul<B> for Vector2<A>
where
A: Mul<B>,
B: Copy,
{
type Output = Vector2<A::Output>;
fn mul(self, rhs: B) -> Self::Output {
Vector2 {
x: self.x * rhs,
y: self.y * rhs,
}
}
}
impl<A, B> DivAssign<B> for Vector2<A>
where
A: DivAssign<B>,
B: Copy,
{
fn div_assign(&mut self, rhs: B) {
self.x /= rhs;
self.y /= rhs;
}
}
impl<A, B> Div<B> for Vector2<A>
where
A: Div<B>,
B: Copy,
{
type Output = Vector2<A::Output>;
fn div(self, rhs: B) -> Self::Output {
Vector2 {
x: self.x / rhs,
y: self.y / rhs,
}
}
}
impl<T> Neg for Vector2<T>
where
T: Neg,
{
type Output = Vector2<T::Output>;
fn neg(self) -> Self::Output {
Vector2 {
x: -self.x,
y: -self.y,
}
}
}
impl<T> Vector2<T>
where
T: Neg<Output = T>,
{
#[must_use]
pub fn perp(self) -> Self {
Self {
x: -self.y,
y: self.x,
}
}
}
#[cfg(feature = "std")]
fn sqrt(v: f32) -> f32 {
v.sqrt()
}
#[cfg(all(not(feature = "std"), feature = "libm"))]
fn sqrt(v: f32) -> f32 {
libm::sqrtf(v)
}