//! # Vec4
//!
//! 4-dimensional vector math for game-engine development,
//! primarily used for homogeneous coordinates.
//!
//! # Example
//!
//! ```rust
//! # use roofy::Vec4;
//! let red: Vec4 = Vec4::new(1.0, 0.0, 0.0, 1.0);
//! let blue: Vec4 = Vec4::new(0.0, 0.0, 1.0, 1.0);
//!
//! let mixed: Vec4 = red.lerp(blue, 0.5);
//!
//! assert_eq!(mixed, Vec4::new(0.5, 0.0, 0.5, 1.0));
//! ```
use std::{
    fmt::Display,
    iter::{Product, Sum},
    ops::{
        Add, AddAssign, Div, DivAssign, Index, IndexMut, Mul, MulAssign, Neg, Rem, RemAssign, Sub,
        SubAssign,
    },
};

use crate::{Quat, Vec2, Vec3};

/// Creates a [`Vec4`](crate::Vec4) from components or a single splat value.
///
/// # Examples
/// ```rust
/// # use roofy::{Vec4, vec4};
/// // From 4 components
/// let v = vec4!(1.0, 2.0, 3.0, 4.0);
/// assert_eq!(v, Vec4::new(1.0, 2.0, 3.0, 4.0));
///
/// // From a single splat value
/// let v = vec4!(0.0);
/// assert_eq!(v, Vec4::ZERO);
///
/// // From Integer literals is accepted.
/// let v = vec4!(1, 2, 3, 4);
/// assert_eq!(v, Vec4::new(1.0, 2.0, 3.0, 4.0));
/// ```
#[macro_export]
macro_rules! vec4 {
    ($x:expr, $y:expr, $z:expr, $w:expr) => {
        $crate::Vec4::new($x as f32, $y as f32, $z as f32, $w as f32)
    };
    ($v:expr) => {
        $crate::Vec4::splat($v as f32)
    };
}

/// 4-dimensional vector, with `f32` components.
/// Same memory layout as `[f32; 4]`.
#[derive(Clone, Copy, Debug, PartialEq)]
#[repr(C)]
pub struct Vec4 {
    /// X component of the vector.
    pub x: f32,
    /// Y component of the vector.
    pub y: f32,
    /// Z component of the vector.
    pub z: f32,
    /// W component of the vector.
    pub w: f32,
}

impl Vec4 {
    /// Threshold for treating a value as zero.
    pub const EPSILON: f32 = 1e-6;
    /// [`EPSILON`](Self::EPSILON) squared.
    pub const EPSILON_SQ: f32 = Self::EPSILON * Self::EPSILON;

    /// Shorthand for writing `Vec4::splat(0.0)`.
    pub const ZERO: Self = Self::splat(0.0);
    /// Shorthand for writing `Vec4::splat(1.0)`.
    pub const ONE: Self = Self::splat(1.0);
    /// Shorthand for writing `Vec4::splat(-1.0)`.
    pub const NEG_ONE: Self = Self::splat(-1.0);
    /// Shorthand for writing `Vec4::splat(f32::INFINITY)`.
    pub const INFINITY: Self = Self::splat(f32::INFINITY);
    /// Shorthand for writing `Vec4::splat(f32::NEG_INFINITY)`.
    pub const NEG_INFINITY: Self = Self::splat(f32::NEG_INFINITY);
    /// Shorthand for writing `Vec4::splat(f32::NAN)`.
    pub const NAN: Self = Self::splat(f32::NAN);

    /// Shorthand for writing `Vec4::new(1.0, 0.0, 0.0, 0.0)`.
    pub const X: Self = Self::new(1.0, 0.0, 0.0, 0.0);
    /// Shorthand for writing `Vec4::new(-1.0, 0.0, 0.0, 0.0)`.
    pub const NEG_X: Self = Self::new(-1.0, 0.0, 0.0, 0.0);
    /// Shorthand for writing `Vec4::new(0.0, 1.0, 0.0, 0.0)`.
    pub const Y: Self = Self::new(0.0, 1.0, 0.0, 0.0);
    /// Shorthand for writing `Vec4::new(0.0, -1.0, 0.0, 0.0)`.
    pub const NEG_Y: Self = Self::new(0.0, -1.0, 0.0, 0.0);
    /// Shorthand for writing `Vec4::new(0.0, 0.0, 1.0, 0.0)`.
    pub const Z: Self = Self::new(0.0, 0.0, 1.0, 0.0);
    /// Shorthand for writing `Vec4::new(0.0, 0.0, -1.0, 0.0)`.
    pub const NEG_Z: Self = Self::new(0.0, 0.0, -1.0, 0.0);
    /// Shorthand for writing `Vec4::new(0.0, 0.0, 0.0, 1.0)`.
    pub const W: Self = Self::new(0.0, 0.0, 0.0, 1.0);
    /// Shorthand for writing `Vec4::new(0.0, 0.0, 0.0, -1.0)`.
    pub const NEG_W: Self = Self::new(0.0, 0.0, 0.0, -1.0);

    /// Creates a `Vec4` with `x`, `y`, `z` and `w` components.
    #[inline(always)]
    #[must_use]
    pub const fn new(x: f32, y: f32, z: f32, w: f32) -> Self {
        Self { x, y, z, w }
    }

    /// Creates a `Vec4` with all components `v`.
    #[inline(always)]
    #[must_use]
    pub const fn splat(v: f32) -> Self {
        Self::new(v, v, v, v)
    }

    /// Creates a `Vec4` from `[x, y, z, w]`
    #[inline]
    #[must_use]
    pub const fn from_array(a: [f32; 4]) -> Self {
        Self::new(a[0], a[1], a[2], a[3])
    }

    /// Creates `[x, y, z, w]` from a `Vec4`.
    #[inline]
    #[must_use]
    pub const fn to_array(self) -> [f32; 4] {
        [self.x, self.y, self.z, self.w]
    }

    /// Creates a `Vec4` from first 4 values of `slice`.
    ///
    /// # Panics
    /// Panics if `slice` is less than 4 elements long.
    #[inline]
    #[must_use]
    pub const fn from_slice(slice: &[f32]) -> Self {
        Self::new(slice[0], slice[1], slice[2], slice[3])
    }

    /// Writes the components of `self` to the first 4 elements of `slice`.
    ///
    /// # Panics
    /// Panics if `slice` is less than 4 elements long.
    #[inline]
    pub fn write_to_slice(self, slice: &mut [f32]) {
        slice[0] = self.x;
        slice[1] = self.y;
        slice[2] = self.z;
        slice[3] = self.w;
    }

    /// Creates a `Vec4` from a `Vec2`, with `z` and `w` set to `0.0`.
    #[inline]
    #[must_use]
    pub const fn from_vec2(v: Vec2) -> Self {
        Self::new(v.x, v.y, 0.0, 0.0)
    }

    /// Creates a `Vec2` from the `x` and `y` components of a `Vec4`, with `z` and `w` discarded.
    ///
    /// Equivalent to [`from_vec4`](Vec2::from_vec4()).
    #[inline]
    #[must_use]
    pub const fn to_vec2(self) -> Vec2 {
        Vec2::from_vec4(self)
    }

    /// Creates a `Vec4` from a `Vec3`, with `w` set to `0.0`.
    #[inline]
    pub const fn from_vec3(v: Vec3) -> Self {
        Self::new(v.x, v.y, v.z, 0.0)
    }

    /// reates a `Vec3` from the `x`, `y` and `z` components of a `Vec4`, discarding `w`.
    ///
    /// Equivalent to [`from_vec4`](Vec3::from_vec4()).
    #[inline]
    #[must_use]
    pub const fn to_vec3(self) -> Vec3 {
        Vec3::from_vec4(self)
    }

    /// Creates a `Vec4` from a `Quat`.
    #[inline]
    #[must_use]
    pub const fn from_quat(q: Quat) -> Self {
        Self::new(q.x, q.y, q.z, q.w)
    }

    /// Creates a `Quat` from a `Vec4`.
    ///
    /// Equivalent to [`from_vec4`](Quat::from_vec4()).
    #[inline]
    #[must_use]
    pub const fn to_quat(self) -> Quat {
        Quat::from_vec4(self)
    }

    /// Returns the component-wise sum of `self` and `rhs`.
    #[inline]
    #[must_use]
    pub const fn add(self, rhs: Self) -> Self {
        Self::new(
            self.x + rhs.x,
            self.y + rhs.y,
            self.z + rhs.z,
            self.w + rhs.w,
        )
    }

    /// Sets `self` to the component-wise sum of `self` and `rhs`.
    #[inline]
    pub const fn add_assign(&mut self, rhs: Self) {
        self.x += rhs.x;
        self.y += rhs.y;
        self.z += rhs.z;
        self.w += rhs.w;
    }

    /// Returns `self` with `rhs` added to each component.
    #[inline]
    #[must_use]
    pub const fn add_scalar(self, rhs: f32) -> Self {
        Self::new(self.x + rhs, self.y + rhs, self.z + rhs, self.w + rhs)
    }

    /// Sets `self` to `self` with `rhs` added to each component.
    #[inline]
    pub const fn add_assign_scalar(&mut self, rhs: f32) {
        self.x += rhs;
        self.y += rhs;
        self.z += rhs;
        self.w += rhs;
    }

    /// Returns the component-wise difference of `self` and `rhs`.
    #[inline]
    #[must_use]
    pub const fn sub(self, rhs: Self) -> Self {
        Self::new(
            self.x - rhs.x,
            self.y - rhs.y,
            self.z - rhs.z,
            self.w - rhs.w,
        )
    }

    /// Sets `self` to the component-wise difference of `self` and `rhs`.
    #[inline]
    pub const fn sub_assign(&mut self, rhs: Self) {
        self.x -= rhs.x;
        self.y -= rhs.y;
        self.z -= rhs.z;
        self.w -= rhs.w;
    }

    /// Returns `self` with `rhs` subtracted from each component.
    #[inline]
    #[must_use]
    pub const fn sub_scalar(self, rhs: f32) -> Self {
        Self::new(self.x - rhs, self.y - rhs, self.z - rhs, self.w - rhs)
    }

    /// Sets `self` to `self` with `rhs` subtracted from each component.
    #[inline]
    pub const fn sub_assign_scalar(&mut self, rhs: f32) {
        self.x -= rhs;
        self.y -= rhs;
        self.z -= rhs;
        self.w -= rhs;
    }

    /// Returns the component-wise product of `self` and `rhs`.
    #[inline]
    #[must_use]
    pub const fn mul(self, rhs: Self) -> Self {
        Self::new(
            self.x * rhs.x,
            self.y * rhs.y,
            self.z * rhs.z,
            self.w * rhs.w,
        )
    }

    /// Sets `self` to the component-wise product of `self` and `rhs`.
    #[inline]
    pub const fn mul_assign(&mut self, rhs: Self) {
        self.x *= rhs.x;
        self.y *= rhs.y;
        self.z *= rhs.z;
        self.w *= rhs.w;
    }

    /// Returns `self` with each component multiplied by `rhs`.
    #[inline]
    #[must_use]
    pub const fn mul_scalar(self, rhs: f32) -> Self {
        Self::new(self.x * rhs, self.y * rhs, self.z * rhs, self.w * rhs)
    }

    /// Sets `self` to `self` with each component multiplied by `rhs`.
    #[inline]
    pub const fn mul_assign_scalar(&mut self, rhs: f32) {
        self.x *= rhs;
        self.y *= rhs;
        self.z *= rhs;
        self.w *= rhs;
    }

    /// Returns the component-wise quotient of `self` and `rhs`.
    #[inline]
    #[must_use]
    pub const fn div(self, rhs: Self) -> Self {
        Self::new(
            self.x / rhs.x,
            self.y / rhs.y,
            self.z / rhs.z,
            self.w / rhs.w,
        )
    }

    /// Sets `self` to the component-wise quotient of `self` and `rhs`.
    #[inline]
    pub const fn div_assign(&mut self, rhs: Self) {
        self.x /= rhs.x;
        self.y /= rhs.y;
        self.z /= rhs.z;
        self.w /= rhs.w;
    }

    /// Returns `self` with each component divided by `rhs`.
    #[inline]
    #[must_use]
    pub const fn div_scalar(self, rhs: f32) -> Self {
        Self::new(self.x / rhs, self.y / rhs, self.z / rhs, self.w / rhs)
    }

    /// Sets `self` to `self` with each component divided by `rhs`.
    #[inline]
    pub const fn div_assign_scalar(&mut self, rhs: f32) {
        self.x /= rhs;
        self.y /= rhs;
        self.z /= rhs;
        self.w /= rhs;
    }

    /// Returns `self` with each component taken modulo `rhs`.
    #[inline]
    #[must_use]
    pub const fn rem(self, rhs: Self) -> Self {
        Self::new(
            self.x % rhs.x,
            self.y % rhs.y,
            self.z % rhs.z,
            self.w % rhs.w,
        )
    }

    /// Sets `self` to `self` with each component taken modulo `rhs`.
    #[inline]
    pub const fn rem_assign(&mut self, rhs: Self) {
        self.x %= rhs.x;
        self.y %= rhs.y;
        self.z %= rhs.z;
        self.w %= rhs.w;
    }

    /// Returns `self` with each component taken modulo `rhs`.
    #[inline]
    #[must_use]
    pub const fn rem_scalar(self, rhs: f32) -> Self {
        Self::new(self.x % rhs, self.y % rhs, self.z % rhs, self.w % rhs)
    }

    /// Sets `self` to `self` with each component taken modulo `rhs`.
    #[inline]
    pub const fn rem_assign_scalar(&mut self, rhs: f32) {
        self.x %= rhs;
        self.y %= rhs;
        self.z %= rhs;
        self.w %= rhs;
    }

    /// Returns `self` with negated components.
    #[inline]
    #[must_use]
    pub const fn neg(self) -> Self {
        Self::new(-self.x, -self.y, -self.z, -self.w)
    }

    /// Returns a reference to the component at `index`.
    ///
    /// `0` maps to `x`, `1` maps to `y`, `2` maps to `z`, `3` maps to `w`.
    ///
    /// # Panics
    /// Panics if `index` is greater than `3`.
    #[inline]
    #[must_use]
    pub const fn index(&self, index: usize) -> &f32 {
        match index {
            0 => &self.x,
            1 => &self.y,
            2 => &self.z,
            3 => &self.w,
            _ => panic!("index out of bounds"),
        }
    }

    /// Returns a mutable reference to the component at `index`.
    ///
    /// `0` maps to `x`, `1` maps to `y`, `2` maps to `z`, `3` maps to `w`.
    ///
    /// # Panics
    /// Panics if `index` is greater than `3`.
    #[inline]
    #[must_use]
    pub const fn index_mut(&mut self, index: usize) -> &mut f32 {
        match index {
            0 => &mut self.x,
            1 => &mut self.y,
            2 => &mut self.z,
            3 => &mut self.w,
            _ => panic!("index out of bounds"),
        }
    }

    /// Returns a reference to the components as `[x, y, z, w]`.
    ///
    /// # Safety
    /// Relies on `Vec4` being `#[repr(C)]`
    #[inline]
    #[must_use]
    pub const fn as_ref(&self) -> &[f32; 4] {
        unsafe { &*(self as *const Vec4 as *const [f32; 4]) }
    }

    /// Returns a reference to the components as `[x, y, z, w]`.
    ///
    /// # Safety
    /// Relies on `Vec4` being `#[repr(C)]`
    #[inline]
    #[must_use]
    pub const fn as_mut(&mut self) -> &mut [f32; 4] {
        unsafe { &mut *(self as *mut Vec4 as *mut [f32; 4]) }
    }

    /// Returns `self` with `f` applied to each component.
    #[inline]
    #[must_use]
    pub fn map<F>(self, mut f: F) -> Self
    where
        F: FnMut(f32) -> f32,
    {
        Self::new(f(self.x), f(self.y), f(self.z), f(self.w))
    }

    /// Returns `self` with the `x` component set to `x`.
    #[inline]
    #[must_use]
    pub const fn with_x(self, x: f32) -> Self {
        Self::new(x, self.y, self.z, self.w)
    }

    /// Returns `self` with the `y` component set to `y`.
    #[inline]
    #[must_use]
    pub const fn with_y(self, y: f32) -> Self {
        Self::new(self.x, y, self.z, self.w)
    }

    /// Returns `self` with the `z` component set to `z`.
    #[inline]
    #[must_use]
    pub const fn with_z(self, z: f32) -> Self {
        Self::new(self.x, self.y, z, self.w)
    }

    /// Returns `self` with the `w` component set to `w`.
    #[inline]
    #[must_use]
    pub const fn with_w(self, w: f32) -> Self {
        Self::new(self.x, self.y, self.y, w)
    }

    /// Returns the dot product of `self` and `other`.
    #[inline]
    #[must_use]
    pub const fn dot(self, other: Self) -> f32 {
        self.x * other.x + self.y * other.y + self.z * other.z + self.w * other.w
    }

    /// Returns the length of `self`.
    #[inline]
    #[must_use]
    pub fn length(self) -> f32 {
        self.dot(self).sqrt()
    }

    /// Returns the squared length of `self`.
    #[inline]
    #[must_use]
    pub const fn length_squared(self) -> f32 {
        self.dot(self)
    }

    /// Normalizes `self`.
    ///
    /// # Preconditions
    /// Expects the length of `self` to not be approximately `0.0` and finite.
    #[inline]
    pub fn normalize(&mut self) {
        *self *= self.length().recip();
    }

    /// Returns `self` normalized.
    ///
    /// # Preconditions
    /// Expects the length of `self` to not be approximately `0.0` and finite.
    #[inline]
    #[must_use]
    pub fn normalized(self) -> Self {
        self * self.length().recip()
    }

    /// Returns `true` and normalizes `self` if the length of `self`
    /// is not approximately `0.0` and finite, otherwise leaves `self` unchanged
    /// and returns `false`.
    ///
    /// Uses [`EPSILON`](Self::EPSILON) as a threshold.
    #[inline]
    #[must_use]
    pub fn try_normalize(&mut self) -> bool {
        let len_sq: f32 = self.length_squared();

        if len_sq < Self::EPSILON_SQ || !len_sq.is_finite() {
            return false;
        }

        self.normalize();
        true
    }

    /// Returns `self` normalized if the length of `self` is not
    /// approximately `0.0` and finite, otherwise returns `None`.
    ///
    /// Uses [`EPSILON`](Self::EPSILON) as a threshold.
    #[inline]
    #[must_use]
    pub fn try_normalized(self) -> Option<Self> {
        let len_sq: f32 = self.length_squared();

        if len_sq < Self::EPSILON_SQ || !len_sq.is_finite() {
            return None;
        }

        Some(self.normalized())
    }

    /// Returns `self` normalized if the length of `self` is not
    /// approximately `0.0` and finite, otherwise returns `fallback`.
    ///
    /// Uses [`EPSILON`](Self::EPSILON) as a threshold.
    #[inline]
    #[must_use]
    pub fn normalized_or(self, fallback: Self) -> Self {
        self.try_normalized().unwrap_or(fallback)
    }

    /// Returns `self` normalized if the length of `self` is not
    /// approximately `0.0` and finite, otherwise returns [`ZERO`](Self::ZERO).
    ///
    /// Uses [`EPSILON`](Self::EPSILON) as a threshold.
    #[inline]
    #[must_use]
    pub fn normalized_or_zero(self) -> Self {
        self.normalized_or(Self::ZERO)
    }

    /// Returns `true` if the length of `self` is approximately `1.0`.
    ///
    /// Uses [`EPSILON`](Self::EPSILON) as a threshold.
    #[inline]
    #[must_use]
    pub const fn is_normalized(self) -> bool {
        (self.length_squared() - 1.0).abs() < Self::EPSILON
    }

    /// Returns the distance from `self` to `to`.
    #[inline]
    #[must_use]
    pub fn distance(self, to: Self) -> f32 {
        (self - to).length()
    }

    /// Returns the distance squared from `self` to `to`.
    #[inline]
    #[must_use]
    pub const fn distance_squared(self, to: Self) -> f32 {
        (self.sub(to)).length_squared()
    }

    /// Returns `self` projected onto `normal`.
    ///
    /// # Edge cases
    /// If `normal` is near-zero, returns [`ZERO`](Self::ZERO).
    #[inline]
    #[must_use]
    pub const fn project(self, normal: Self) -> Self {
        let len_sq: f32 = normal.length_squared();

        if len_sq < Self::EPSILON_SQ {
            return Self::ZERO;
        }

        normal.mul_scalar(self.dot(normal) / len_sq)
    }

    /// Returns a `Vec4` with the smallest components of `self` and `other`.
    #[inline]
    #[must_use]
    pub const fn min(self, other: Self) -> Self {
        Self::new(
            self.x.min(other.x),
            self.y.min(other.y),
            self.z.min(other.z),
            self.w.min(other.w),
        )
    }

    /// Returns a `Vec4` with the largest components of `self` and `other`.
    #[inline]
    #[must_use]
    pub const fn max(self, other: Self) -> Self {
        Self::new(
            self.x.max(other.x),
            self.y.max(other.y),
            self.z.max(other.z),
            self.w.max(other.w),
        )
    }

    /// Returns a `Vec4` with components of `self` clamped between corresponding components of `min` and `max`.
    ///
    /// # Preconditions
    /// Expects each component of `min` to be less than or equal to the corresponding component of `max`.
    #[inline]
    #[must_use]
    pub const fn clamp(self, min: Self, max: Self) -> Self {
        self.max(min).min(max)
    }

    /// Returns `self` with the absolute value of each component.
    #[inline]
    #[must_use]
    pub const fn abs(self) -> Self {
        Self::new(self.x.abs(), self.y.abs(), self.z.abs(), self.w.abs())
    }

    /// Returns `self` with the sign of each component.
    ///
    /// - `1.0` if the number is positive, `+0.0` or `INFINITY`
    /// - `-1.0` if the number is negative, `-0.0` or `NEG_INFINITY`
    /// - `NaN`` if the number is `NaN`
    #[inline]
    #[must_use]
    pub const fn signum(self) -> Self {
        Self::new(
            self.x.signum(),
            self.y.signum(),
            self.z.signum(),
            self.w.signum(),
        )
    }

    /// Returns `self` with each component raised to the power of `n`.
    #[inline]
    #[must_use]
    pub fn powf(self, n: f32) -> Self {
        Self::new(
            self.x.powf(n),
            self.y.powf(n),
            self.z.powf(n),
            self.w.powf(n),
        )
    }

    /// Returns `self` with the square root value of each component.
    #[inline]
    #[must_use]
    pub fn sqrt(self) -> Self {
        Self::new(self.x.sqrt(), self.y.sqrt(), self.z.sqrt(), self.w.sqrt())
    }

    /// Returns `self` with the sine value of each component.
    #[inline]
    #[must_use]
    pub fn sin(self) -> Self {
        Self::new(self.x.sin(), self.y.sin(), self.z.sin(), self.w.sin())
    }

    /// Returns `self` with the cosine value of each component.
    #[inline]
    #[must_use]
    pub fn cos(self) -> Self {
        Self::new(self.x.cos(), self.y.cos(), self.z.cos(), self.w.cos())
    }

    /// Returns a `(Vec4, Vec4)` with the sine and cosine value of each component of `self`.
    #[inline]
    #[must_use]
    pub fn sin_cos(self) -> (Self, Self) {
        let (sin_x, cos_x): (f32, f32) = self.x.sin_cos();
        let (sin_y, cos_y): (f32, f32) = self.y.sin_cos();
        let (sin_z, cos_z): (f32, f32) = self.z.sin_cos();
        let (sin_w, cos_w): (f32, f32) = self.w.sin_cos();

        (
            Self::new(sin_x, sin_y, sin_z, sin_w),
            Self::new(cos_x, cos_y, cos_z, cos_w),
        )
    }

    /// Returns `self` with the reciprocal value of each component.
    #[inline]
    #[must_use]
    pub const fn recip(self) -> Self {
        Self::new(
            self.x.recip(),
            self.y.recip(),
            self.z.recip(),
            self.w.recip(),
        )
    }

    /// Returns `self` with the nearest integer to each component.
    /// If a component is half-way between two integers, round away from 0.0.
    #[inline]
    #[must_use]
    pub const fn round(self) -> Self {
        Self::new(
            self.x.round(),
            self.y.round(),
            self.z.round(),
            self.w.round(),
        )
    }

    /// Returns `self` with the largest integer less than or equal to each component.
    #[inline]
    #[must_use]
    pub const fn floor(self) -> Self {
        Self::new(
            self.x.floor(),
            self.y.floor(),
            self.z.floor(),
            self.w.floor(),
        )
    }

    /// Returns `self` with the smallest integer less than or equal to each component.
    #[inline]
    #[must_use]
    pub const fn ceil(self) -> Self {
        Self::new(self.x.ceil(), self.y.ceil(), self.z.ceil(), self.w.ceil())
    }

    /// Returns a `Vec4` linearly interpolated between `self` and `to`, with factor `t`.
    #[inline]
    #[must_use]
    pub const fn lerp(self, to: Self, t: f32) -> Self {
        self.add(to.sub(self).mul_scalar(t))
    }

    /// Returns a `Vec4` linearly interpolated between `self` and `to`, with factor `t`.
    ///
    /// Clamps `t` between `0.0` and `1.0`.
    #[inline]
    #[must_use]
    pub const fn lerp_clamped(self, to: Self, t: f32) -> Self {
        self.lerp(to, t.clamp(0.0, 1.0))
    }

    /// Returns a `Vec4` incrementally moved from `self` to `to`, by at most `max_delta` distance,
    /// without overshooting.
    #[inline]
    #[must_use]
    pub fn move_towards(self, to: Self, max_delta: f32) -> Self {
        let delta: Self = to - self;
        let distance: f32 = delta.length();

        if distance < Self::EPSILON || distance <= max_delta {
            return to;
        }

        self + delta / distance * max_delta
    }

    /// Returns `true` if `self` and `other` approximately represent the same point or direction.
    ///
    /// Uses [`EPSILON`](Self::EPSILON) as the threshold.
    #[inline]
    #[must_use]
    pub const fn approx_eq(self, other: Self) -> bool {
        self.distance_squared(other) < Self::EPSILON_SQ
    }

    /// Returns `true` if all components of `self` are finite.
    #[inline]
    #[must_use]
    pub const fn is_finite(self) -> bool {
        self.x.is_finite() && self.y.is_finite() && self.z.is_finite() && self.w.is_finite()
    }

    /// Returns `true` if any components of `self` is `NaN`.
    #[inline]
    #[must_use]
    pub const fn is_nan(self) -> bool {
        self.x.is_nan() || self.y.is_nan() || self.z.is_nan() || self.w.is_nan()
    }
}

impl Add for Vec4 {
    type Output = Self;

    /// Returns the component-wise sum of `self` and `rhs`.
    ///
    /// Equivalent to [`add`](Self::add()).
    fn add(self, rhs: Self) -> Self::Output {
        self.add(rhs)
    }
}

impl AddAssign for Vec4 {
    /// Sets `self` to the component-wise sum of `self` and `rhs`.
    ///
    /// Equivalent to [`add_assign`](Self::add_assign()).
    #[inline]
    fn add_assign(&mut self, rhs: Self) {
        self.add_assign(rhs);
    }
}

impl Add<f32> for Vec4 {
    type Output = Self;

    /// Returns `self` with `rhs` added to each component.
    ///
    /// Equivalent to [`add_scalar`](Self::add_scalar()).
    #[inline]
    fn add(self, rhs: f32) -> Self::Output {
        self.add_scalar(rhs)
    }
}

impl AddAssign<f32> for Vec4 {
    /// Sets `self` to `self` with `rhs` added to each component.
    ///
    /// Equivalent to [`add_assign_scalar`](Self::add_assign_scalar()).
    #[inline]
    fn add_assign(&mut self, rhs: f32) {
        self.add_assign_scalar(rhs);
    }
}

impl Add<Vec4> for f32 {
    type Output = Vec4;

    /// Returns `rhs` with `self` added to each component.
    ///
    /// Equivalent to [`add_scalar`](Vec4::add_scalar()).
    #[inline]
    fn add(self, rhs: Vec4) -> Self::Output {
        rhs.add_scalar(self)
    }
}

impl Sub for Vec4 {
    type Output = Self;

    /// Returns the component-wise difference of `self` and `rhs`.
    ///
    /// Equivalent to [`sub`](Self::sub()).
    #[inline]
    fn sub(self, rhs: Self) -> Self::Output {
        self.sub(rhs)
    }
}

impl SubAssign for Vec4 {
    /// Sets `self` to the component-wise difference of `self` and `rhs`.
    ///
    /// Equivalent to [`sub_assign`](Self::sub_assign()).
    #[inline]
    fn sub_assign(&mut self, rhs: Self) {
        self.sub_assign(rhs);
    }
}

impl Sub<f32> for Vec4 {
    type Output = Self;

    /// Returns `self` with `rhs` subtracted from each component.
    ///
    /// Equivalent to [`sub_scalar`](Self::sub_scalar()).
    #[inline]
    fn sub(self, rhs: f32) -> Self::Output {
        self.sub_scalar(rhs)
    }
}

impl SubAssign<f32> for Vec4 {
    /// Sets `self` to `self` with `rhs` subtracted from each component.
    ///
    /// Equivalent to [`sub_assign_scalar`](Self::sub_assign_scalar()).
    #[inline]
    fn sub_assign(&mut self, rhs: f32) {
        self.sub_assign_scalar(rhs);
    }
}

impl Mul for Vec4 {
    type Output = Self;

    /// Returns the component-wise product of `self` and `rhs`.
    ///
    /// Equivalent to [`mul`](Self::mul()).
    #[inline]
    fn mul(self, rhs: Self) -> Self::Output {
        self.mul(rhs)
    }
}

impl MulAssign for Vec4 {
    /// Sets `self` to the component-wise product of `self` and `rhs`.
    ///
    /// Equivalent to [`mul_assign`](Self::mul_assign()).
    #[inline]
    fn mul_assign(&mut self, rhs: Self) {
        self.mul_assign(rhs);
    }
}

impl Mul<f32> for Vec4 {
    type Output = Self;

    /// Returns `self` with each component multiplied by `rhs`.
    ///
    /// Equivalent to [`mul_scalar`](Self::mul_scalar()).
    #[inline]
    fn mul(self, rhs: f32) -> Self::Output {
        self.mul_scalar(rhs)
    }
}

impl MulAssign<f32> for Vec4 {
    /// Sets `self` to `self` with each component multiplied by `rhs`.
    ///
    /// Equivalent to [`mul_assign_scalar`](Self::mul_assign_scalar()).
    #[inline]
    fn mul_assign(&mut self, rhs: f32) {
        self.mul_assign_scalar(rhs);
    }
}

impl Mul<Vec4> for f32 {
    type Output = Vec4;

    /// Returns `rhs` with each component multiplied by `self`.
    ///
    /// Equivalent to [`mul_scalar`](Vec4::mul_scalar()).
    #[inline]
    fn mul(self, rhs: Vec4) -> Self::Output {
        rhs.mul_scalar(self)
    }
}

impl Div for Vec4 {
    type Output = Self;

    /// Returns the component-wise quotient of `self` and `rhs`.
    ///
    /// Equivalent to [`div`](Self::div()).
    #[inline]
    fn div(self, rhs: Self) -> Self::Output {
        self.div(rhs)
    }
}

impl DivAssign for Vec4 {
    /// Sets `self` to the component-wise quotient of `self` and `rhs`.
    ///
    /// Equivalent to [`div_assign`](Self::div_assign()).
    #[inline]
    fn div_assign(&mut self, rhs: Self) {
        self.div_assign(rhs);
    }
}

impl Div<f32> for Vec4 {
    type Output = Self;

    /// Returns `self` with each component divided by `rhs`.
    ///
    /// Equivalent to [`div_scalar`](Self::div_scalar()).
    #[inline]
    fn div(self, rhs: f32) -> Self::Output {
        self.div_scalar(rhs)
    }
}

impl DivAssign<f32> for Vec4 {
    /// Sets `self` to `self` with each component divided by `rhs`.
    ///
    /// Equivalent to [`div_assign_scalar`](Self::div_assign_scalar()).
    #[inline]
    fn div_assign(&mut self, rhs: f32) {
        self.div_assign_scalar(rhs)
    }
}

impl Rem for Vec4 {
    type Output = Self;

    /// Returns `self` with each component taken modulo `rhs`.
    ///
    /// Equivalent to [`rem`](Self::rem()).
    #[inline]
    fn rem(self, rhs: Self) -> Self::Output {
        self.rem(rhs)
    }
}

impl RemAssign for Vec4 {
    /// Sets `self` to `self` with each component taken modulo `rhs`.
    ///
    /// Equivalent to [`rem_assign`](Self::rem_assign()).
    #[inline]
    fn rem_assign(&mut self, rhs: Self) {
        self.rem_assign(rhs);
    }
}

impl Rem<f32> for Vec4 {
    type Output = Self;

    /// Returns `self` with each component taken modulo `rhs`.
    ///
    /// Equivalent to [`rem_scalar`](Self::rem_scalar()).
    #[inline]
    fn rem(self, rhs: f32) -> Self::Output {
        self.rem_scalar(rhs)
    }
}

impl RemAssign<f32> for Vec4 {
    /// Sets `self` to `self` with each component taken modulo `rhs`.
    ///
    /// Equivalent to [`rem_assign_scalar`](Self::rem_assign_scalar()).
    #[inline]
    fn rem_assign(&mut self, rhs: f32) {
        self.rem_assign_scalar(rhs);
    }
}

impl Neg for Vec4 {
    type Output = Self;

    /// Returns `self` with negated components.
    ///
    /// Equivalent to [`neg`](Self::neg()).
    #[inline]
    fn neg(self) -> Self::Output {
        self.neg()
    }
}

impl Index<usize> for Vec4 {
    type Output = f32;

    /// Returns a reference to the component at `index`.
    ///
    /// `0` maps to `x`, `1` maps to `y`, `2` maps to `z`, `3` maps to `w`.
    ///
    /// Equivalent to [`index`](Self::index()).
    ///
    /// # Panics
    /// Panics if `index` is greater than `3`.
    #[inline]
    fn index(&self, index: usize) -> &Self::Output {
        self.index(index)
    }
}

impl IndexMut<usize> for Vec4 {
    /// Returns a mutable reference to the component at `index`.
    ///
    /// `0` maps to `x`, `1` maps to `y`, `2` maps to `z`, `3` maps to `w`.
    ///
    /// Equivalent to [`index_mut`](Self::index_mut()).
    ///
    /// # Panics
    /// Panics if `index` is greater than `3`.
    #[inline]
    fn index_mut(&mut self, index: usize) -> &mut Self::Output {
        self.index_mut(index)
    }
}

impl AsRef<[f32; 4]> for Vec4 {
    /// Returns a reference to the components as `[x, y, z, w]`.
    ///
    /// Equivalent to [`as_ref`](Self::as_ref()).
    ///
    /// # Safety
    /// Relies on `Vec4` being `#[repr(C)]`
    #[inline]
    fn as_ref(&self) -> &[f32; 4] {
        self.as_ref()
    }
}

impl AsMut<[f32; 4]> for Vec4 {
    /// Returns a reference to the components as `[x, y, z, w]`.
    ///
    /// Equivalent to [`as_mut`](Self::as_mut()).
    ///
    /// # Safety
    /// Relies on `Vec4` being `#[repr(C)]`
    #[inline]
    fn as_mut(&mut self) -> &mut [f32; 4] {
        self.as_mut()
    }
}

impl Sum for Vec4 {
    /// Sums an iterator of `Vec4` by component-wise addition, starting from [`ZERO`](Self::ZERO).
    #[inline]
    fn sum<I: Iterator<Item = Self>>(iter: I) -> Self {
        iter.fold(Self::ZERO, Self::add)
    }
}

impl<'a> Sum<&'a Vec4> for Vec4 {
    /// Sums an iterator of `Vec4` by component-wise addition, starting from [`ZERO`](Self::ZERO).
    #[inline]
    fn sum<I: Iterator<Item = &'a Self>>(iter: I) -> Self {
        iter.fold(Self::ZERO, |a, &b| a.add(b))
    }
}

impl Product for Vec4 {
    /// Multiplies an iterator of `Vec4` component-wise, starting from [`ONE`](Self::ONE).
    #[inline]
    fn product<I: Iterator<Item = Self>>(iter: I) -> Self {
        iter.fold(Self::ONE, Self::mul)
    }
}

impl<'a> Product<&'a Vec4> for Vec4 {
    /// Multiplies an iterator of `Vec4` component-wise, starting from [`ONE`](Self::ONE).
    #[inline]
    fn product<I: Iterator<Item = &'a Self>>(iter: I) -> Self {
        iter.fold(Self::ONE, |a, &b| a.mul(b))
    }
}

impl Display for Vec4 {
    /// Formats `self` as `(x, y, z, w)`.
    ///
    /// Respects the precision of `f`.
    #[inline]
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        if let Some(p) = f.precision() {
            write!(
                f,
                "({:.*}, {:.*}, {:.*}, {:.*})",
                p, self.x, p, self.y, p, self.z, p, self.w
            )
        } else {
            write!(f, "({}, {}, {}, {})", self.x, self.y, self.z, self.w)
        }
    }
}

impl Default for Vec4 {
    /// Default is [`ZERO`](Self::ZERO).
    #[inline]
    fn default() -> Self {
        Self::ZERO
    }
}

impl From<[f32; 4]> for Vec4 {
    /// Creates a `Vec4` from `[x, y, z, w]`
    ///
    /// Equivalent to [`from_array`](Self::from_array()).
    #[inline]
    fn from(v: [f32; 4]) -> Self {
        Self::from_array(v)
    }
}

impl From<Vec4> for [f32; 4] {
    /// Creates `[x, y, z, w]` from a `Vec4`.
    ///
    /// Equivalent to [`to_array`](Vec4::to_array()).
    #[inline]
    fn from(v: Vec4) -> Self {
        v.to_array()
    }
}

impl From<&[f32]> for Vec4 {
    /// Creates a `Vec4` from first 4 values of `v`.
    ///
    /// Equivalent to [`from_slice`](Self::from_slice()).
    ///
    /// # Panics
    /// Panics if `v` is less than 4 elements long.
    #[inline]
    fn from(v: &[f32]) -> Self {
        Self::from_slice(v)
    }
}

impl From<Vec2> for Vec4 {
    /// Creates a `Vec4` from a `Vec2`, with `z` and `w` set to `0.0`.
    ///
    /// Equivalent to [`from_vec2`](Self::from_vec2()).
    #[inline]
    fn from(v: Vec2) -> Self {
        Self::from_vec2(v)
    }
}

impl From<Vec3> for Vec4 {
    /// Creates a `Vec4` from a `Vec3`, with `w` set to `0.0`.
    ///
    /// Equivalent to [`from_vec3`](Self::from_vec3()).
    #[inline]
    fn from(v: Vec3) -> Self {
        Self::from_vec3(v)
    }
}

impl From<Quat> for Vec4 {
    /// Creates a `Vec4` from a `Quat`.
    ///
    /// Equivalent to [`from_quat`](Self::from_quat()).
    #[inline]
    fn from(q: Quat) -> Self {
        Self::from_quat(q)
    }
}

#[cfg(feature = "serde")]
impl serde::Serialize for Vec4 {
    /// Serializes as `[x, y, z, w]`.
    ///
    /// # Format
    /// Encoded as a flat 4-element array. Component order matches [`to_array`](Self::to_array()).
    fn serialize<S: serde::Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
        self.to_array().serialize(serializer)
    }
}

#[cfg(feature = "serde")]
impl<'de> serde::Deserialize<'de> for Vec4 {
    /// Deserializes from `[x, y, z, w]`.
    ///
    /// # Format
    /// Decoded as a flat 4-element array. Component order matches [`from_array`](Self::from_array()).
    ///
    /// # Errors
    /// Returns an error if array is not exactly 4 elements.
    fn deserialize<D: serde::Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
        <[f32; 4]>::deserialize(deserializer).map(Self::from_array)
    }
}

#[cfg(feature = "bytemuck")]
unsafe impl bytemuck::Zeroable for Vec4 {}

#[cfg(feature = "bytemuck")]
unsafe impl bytemuck::Pod for Vec4 {}
