//! # Vec3
//!
//! 3-dimensional vector math for game-engine development and graphics.
//!
//! # Example
//!
//! ```rust
//! # use roofy::Vec3;
//! let player: Vec3 = Vec3::ZERO;
//! let target: Vec3 = Vec3::new(3.0, 0.0, 4.0);
//!
//! let direction: Vec3 = (target - player).normalized();
//! let speed: f32 = 10.0;
//! let velocity: Vec3 = direction * speed;
//!
//! assert_eq!(direction, Vec3::new(0.6, 0.0, 0.8));
//! assert_eq!(velocity, Vec3::new(6.0, 0.0, 8.0));
//! ```
use std::{
    fmt::{Debug, Display},
    iter::{Product, Sum},
    ops::{
        Add, AddAssign, Div, DivAssign, Index, IndexMut, Mul, MulAssign, Neg, Rem, RemAssign, Sub,
        SubAssign,
    },
};

use crate::{Vec2, Vec4};

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

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

impl Vec3 {
    /// 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 `Vec3::splat(0.0)`.
    pub const ZERO: Self = Self::splat(0.0);
    /// Shorthand for writing `Vec3::splat(1.0)`.
    pub const ONE: Self = Self::splat(1.0);
    /// Shorthand for writing `Vec3::splat(-1.0)`.
    pub const NEG_ONE: Self = Self::splat(-1.0);
    /// Shorthand for writing `Vec3::splat(f32::INFINITY)`.
    pub const INFINITY: Self = Self::splat(f32::INFINITY);
    /// Shorthand for writing `Vec3::splat(f32::NEG_INFINITY)`.
    pub const NEG_INFINITY: Self = Self::splat(f32::NEG_INFINITY);
    /// Shorthand for writing `Vec3::splat(f32::NAN)`.
    pub const NAN: Self = Self::splat(f32::NAN);

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

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

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

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

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

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

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

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

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

    /// Creates a `Vec3` from the `x`, `y` and `z` components of a `Vec4`, discarding `w`.
    #[inline]
    pub const fn from_vec4(v: Vec4) -> Self {
        Self::new(v.x, v.y, v.z)
    }

    /// Creates a `Vec4` from a `Vec2`, with `z` and `w` set to `0.0`.
    ///
    /// Equivalent to [`from_vec3`](Vec4::from_vec3()).
    #[inline]
    #[must_use]
    pub const fn to_vec4(self) -> Vec4 {
        Vec4::from_vec3(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)
    }

    /// 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;
    }

    /// 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)
    }

    /// 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;
    }

    /// 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)
    }

    /// 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;
    }

    /// 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)
    }

    /// 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;
    }

    /// 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)
    }

    /// 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;
    }

    /// 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)
    }

    /// 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;
    }

    /// 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)
    }

    /// 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;
    }

    /// 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)
    }

    /// 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;
    }

    /// 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)
    }

    /// 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;
    }

    /// 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)
    }

    /// 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;
    }

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

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

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

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

    /// 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))
    }

    /// 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)
    }

    /// 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)
    }

    /// 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)
    }

    /// 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
    }

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

    /// 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 a `Vec3` with direction of `self` and length clamped between `min_length` and `max_length`.
    ///
    /// # Preconditions
    /// Expects `min_length` to be non-negative and less than or equal to `max_length`.
    ///
    /// # Edge cases
    /// If `self` is near-zero, returns [`ZERO`](Self::ZERO).
    #[inline]
    #[must_use]
    pub fn clamp_length(self, min_length: f32, max_length: f32) -> Self {
        let len_sq: f32 = self.length_squared();

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

        let len: f32 = len_sq.sqrt();
        let clamped: f32 = len.clamp(min_length, max_length);

        if clamped == len {
            return self;
        }

        self * (clamped / len)
    }

    /// Returns the angle between `self` and `to` in radians.
    ///
    /// # Edge cases
    /// If either vector is near-zero, returns `0.0`.
    #[inline]
    #[must_use]
    pub fn angle_between(self, to: Self) -> f32 {
        let len_sq: f32 = self.length_squared() * to.length_squared();

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

        (self.dot(to) / len_sq.sqrt()).clamp(-1.0, 1.0).acos()
    }

    /// Returns the angle between `self` and `to` in degrees.
    ///
    /// # Edge cases
    /// If either vector is near-zero, returns `0.0`.
    #[inline]
    #[must_use]
    pub fn angle_between_degrees(self, to: Self) -> f32 {
        self.angle_between(to).to_degrees()
    }

    /// 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`.
    ///
    /// # Preconditions
    /// Expects `normal` to be normalized.
    ///
    /// # Edge cases
    /// If `normal` is near-zero, returns [`ZERO`](Self::ZERO).
    #[inline]
    #[must_use]
    pub const fn project(self, normal: Self) -> Self {
        if normal.length_squared() < Self::EPSILON_SQ {
            return Self::ZERO;
        }

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

    /// Returns `self` projected onto the plane `normal`.
    ///
    /// # Preconditions
    /// Expects `normal` to be normalized.
    ///
    /// # Edge cases
    /// If `normal` is near-zero, returns `self`.
    #[inline]
    #[must_use]
    pub const fn project_on_plane(self, normal: Self) -> Self {
        self.sub(self.project(normal))
    }

    /// Returns `self` reflected off `normal`.
    ///
    /// # Preconditions
    /// Expects `normal` to be normalized.
    #[inline]
    #[must_use]
    pub const fn reflect(self, normal: Self) -> Self {
        self.sub(normal.mul_scalar(2.0 * self.dot(normal)))
    }

    /// Returns a `Vec3` 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),
        )
    }

    /// Returns a `Vec3` 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),
        )
    }

    /// Returns a `Vec3` 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())
    }

    /// 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())
    }

    /// 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))
    }

    /// 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())
    }

    /// 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())
    }

    /// 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())
    }

    /// Returns a `(Vec3, Vec3)` 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();

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

    /// 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())
    }

    /// 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())
    }

    /// 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())
    }

    /// 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())
    }

    /// Returns a `Vec3` 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 `Vec3` 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 `Vec3` spherically interpolated between `self` and `to`, with factor `t`.
    ///
    /// # Preconditions
    /// Expects `self` and `to` to be normalized.
    ///
    /// # Edge cases
    /// For antiparallel vectors, the result is numerically unstable
    /// and may be `NaN` or otherwise meaningless.
    #[inline]
    #[must_use]
    pub fn slerp(self, to: Self, t: f32) -> Self {
        let theta: f32 = self.dot(to).clamp(-1.0, 1.0).acos();

        if theta.abs() < Self::EPSILON {
            return self.lerp(to, t);
        }

        let sin_theta: f32 = theta.sin();

        let a: f32 = ((1.0 - t) * theta).sin() / sin_theta;
        let b: f32 = (t * theta).sin() / sin_theta;
        self * a + to * b
    }

    /// Returns a `Vec3` spherically interpolated between `self` and `to`, with factor `t`.
    ///
    /// Clamps `t` between `0.0` and `1.0`.
    ///
    /// # Preconditions
    /// Expects `self` and `to` to be normalized.
    ///
    /// # Undefined behaviour
    /// Behavior undefined for antiparallel vectors.
    #[inline]
    #[must_use]
    pub fn slerp_clamped(self, to: Self, t: f32) -> Self {
        self.slerp(to, t.clamp(0.0, 1.0))
    }

    /// Returns a `Vec3` 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 a `Vec3` rotated from `self` to `to` by at most `max_angle` radians
    /// and interpolates length towards `max_len`.
    #[must_use]
    pub fn rotate_towards(self, to: Self, max_angle: f32, max_len_delta: f32) -> Self {
        let len: f32 = self.length();
        let to_len: f32 = to.length();

        if len < Self::EPSILON || to_len < Self::EPSILON {
            return to;
        }

        let dir: Self = self / len;
        let to_dir: Self = to / to_len;

        let angle: f32 = dir.dot(to_dir).clamp(-1.0, 1.0).acos();

        let new_dir: Self = if angle <= Self::EPSILON || angle <= max_angle {
            to_dir
        } else {
            dir.slerp(to_dir, max_angle / angle)
        };

        let len_delta: f32 = to_len - len;

        let new_len: f32 = if len_delta.abs() <= max_len_delta {
            to_len
        } else {
            len + len_delta.signum() * max_len_delta
        };

        new_dir * new_len
    }

    /// Returns `true` if `self` and `other` approximately represent the same point.
    ///
    /// 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()
    }

    /// 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()
    }
}

impl Add for Vec3 {
    type Output = Self;

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

impl AddAssign for Vec3 {
    /// 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 Vec3 {
    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 Vec3 {
    /// 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<Vec3> for f32 {
    type Output = Vec3;

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

impl Sub for Vec3 {
    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 Vec3 {
    /// 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 Vec3 {
    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 Vec3 {
    /// 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 Vec3 {
    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 Vec3 {
    /// 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 Vec3 {
    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 Vec3 {
    /// 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<Vec3> for f32 {
    type Output = Vec3;

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

impl Div for Vec3 {
    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 Vec3 {
    /// 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 Vec3 {
    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 Vec3 {
    /// 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 Vec3 {
    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 Vec3 {
    /// 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 Vec3 {
    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 Vec3 {
    /// 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 Vec3 {
    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 Vec3 {
    type Output = f32;

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

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

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

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

impl Sum for Vec3 {
    /// Sums an iterator of `Vec3` 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 Vec3> for Vec3 {
    /// Sums an iterator of `Vec3` 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 Vec3 {
    /// Multiplies an iterator of `Vec3` 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 Vec3> for Vec3 {
    /// Multiplies an iterator of `Vec3` 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 Vec3 {
    /// Formats `self` as `(x, y, z)`.
    ///
    /// 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)
        } else {
            write!(f, "({}, {}, {})", self.x, self.y, self.z)
        }
    }
}

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

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

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

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

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

impl From<Vec4> for Vec3 {
    /// Creates a `Vec3` from the `x`, `y` and `z` components of a `Vec4`, discarding `w`.
    ///
    /// Equivalent to [`from_vec4`](Self::from_vec4()).
    #[inline]
    fn from(v: Vec4) -> Self {
        Self::from_vec4(v)
    }
}

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

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

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