//! # Vec3
//!
//! 3-dimensional vector math for game-engine development and graphics.
//!
//! # Conventions
//!
//! - Angles are in radians, unless otherwise stated
//!
//! # Example
//!
//! ```rust
//! # use roofy::math::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},
    ops::{
        Add, AddAssign, Div, DivAssign, Index, IndexMut, Mul, MulAssign, Neg, Rem, RemAssign, Sub,
        SubAssign,
    },
};

use crate::math::{Vec2, Vec4};

/// 3-dimensional vector, with `f32` components.
/// Same memory layout as `[f32; 3]`, making it safe for GPU uploads.
#[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]
    #[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]
    #[must_use]
    pub const fn splat(v: f32) -> Self {
        Self::new(v, v, v)
    }

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

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

    /// Normalizes `self` to have a length of 1, while preserving direction.
    ///
    /// # Edge cases
    /// If `self` is near-zero, sets `self` to [`ZERO`](Self::ZERO).
    #[inline]
    pub fn normalize(&mut self) {
        let len_sq: f32 = self.length_squared();

        if len_sq < Self::EPSILON_SQ {
            *self = Self::ZERO;
            return;
        }

        *self *= 1.0 / len_sq.sqrt();
    }

    /// Returns a unit-length `Vec3` with direction of `self`.
    ///
    /// # Edge cases
    /// If `self` is near-zero, returns [`ZERO`](Self::ZERO).
    #[inline]
    #[must_use]
    pub fn normalized(self) -> Self {
        let len_sq: f32 = self.length_squared();

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

        self * (1.0 / len_sq.sqrt())
    }

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

    /// 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 angle between `self` and `to` in radians.
    ///
    /// # Edge cases
    /// If either vector is near-zero, returns `0.0`.
    #[inline]
    #[must_use]
    pub fn angle(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_degrees(self, to: Self) -> f32 {
        self.angle(to).to_degrees()
    }

    /// 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 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 fn distance_squared(self, to: Self) -> f32 {
        (self - to).length_squared()
    }

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

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

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

    /// Returns `self` projected onto the plane `normal`.
    ///
    /// # Precondition
    /// Expects `normal` to be normalized.
    #[inline]
    #[must_use]
    pub fn project_on_plane(self, normal: Self) -> Self {
        self - self.project(normal)
    }

    /// Returns `self` reflected off `normal`.
    ///
    /// # Precondition
    /// Expects `normal` to be normalized.
    #[inline]
    #[must_use]
    pub const fn reflect(self, normal: Self) -> Self {
        let factor: f32 = -2.0 * self.dot(normal);
        Self::new(
            factor * normal.x + self.x,
            factor * normal.y + self.y,
            factor * normal.z + self.z,
        )
    }

    /// 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`.
    ///
    /// # Precondition
    /// 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 a `Vec3` with the absolute value of each component of `self`.
    #[inline]
    #[must_use]
    pub const fn abs(self) -> Self {
        Self::new(self.x.abs(), self.y.abs(), self.z.abs())
    }

    /// Returns a `Vec3` with each component of `self` 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 a `Vec3` with the square root value of each component of `self`.
    #[inline]
    #[must_use]
    pub fn sqrt(self) -> Self {
        Self::new(self.x.sqrt(), self.y.sqrt(), self.z.sqrt())
    }

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

    /// Returns a `Vec3` with the cosine value of each component of `self`.
    #[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 a `Vec3` with the reciprocal value of each component of `self`.
    #[inline]
    #[must_use]
    pub const fn recip(self) -> Self {
        Self::new(self.x.recip(), self.y.recip(), self.z.recip())
    }

    /// Returns a `Vec3` with direction of `self` and length clamped between `min_length` and `max_length`.
    ///
    /// # Precondition
    /// 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 a `Vec3` linearly interpolated between `self` and `to`, with factor `t`.
    #[inline]
    #[must_use]
    pub fn lerp(self, to: Self, t: f32) -> Self {
        self + (to - self) * 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 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`.
    ///
    /// # Precondition
    /// 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`.
    ///
    /// # Precondition
    /// 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` (in 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 a `[f32; 3]` copy of the components.
    #[inline]
    #[must_use]
    pub const fn to_array(self) -> [f32; 3] {
        [self.x, self.y, self.z]
    }

    /// Returns `true` if `self` and `other` approximately represent the same point.
    ///
    /// Uses [`EPSILON`](Self::EPSILON) as threshold.
    #[inline]
    #[must_use]
    pub 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 a `Vec3` with the coresponding components of `rhs`
    /// added to `self`.
    #[inline]
    fn add(self, rhs: Self) -> Self::Output {
        Self::new(self.x + rhs.x, self.y + rhs.y, self.z + rhs.z)
    }
}

impl AddAssign for Vec3 {
    /// Adds the corresponding components of `rhs` to `self`.
    #[inline]
    fn add_assign(&mut self, rhs: Self) {
        self.x += rhs.x;
        self.y += rhs.y;
        self.z += rhs.z;
    }
}

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

    /// Returns a `Vec3` with `rhs` added to each component of `self`.
    #[inline]
    fn add(self, rhs: f32) -> Self::Output {
        Self::new(self.x + rhs, self.y + rhs, self.z + rhs)
    }
}

impl AddAssign<f32> for Vec3 {
    /// Adds `rhs` to each component of `self`.
    #[inline]
    fn add_assign(&mut self, rhs: f32) {
        self.x += rhs;
        self.y += rhs;
        self.z += rhs;
    }
}

impl Sub for Vec3 {
    type Output = Self;

    /// Returns a `Vec3` with the corresponding components of `rhs`
    /// subtracted from `self`.
    #[inline]
    fn sub(self, rhs: Self) -> Self::Output {
        Self::new(self.x - rhs.x, self.y - rhs.y, self.z - rhs.z)
    }
}

impl SubAssign for Vec3 {
    /// Subtracts the corresponding components of `rhs` from `self`.
    #[inline]
    fn sub_assign(&mut self, rhs: Self) {
        self.x -= rhs.x;
        self.y -= rhs.y;
        self.z -= rhs.z;
    }
}

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

    /// Returns a `Vec3` with `rhs` subtracted from each component of `self`.
    #[inline]
    fn sub(self, rhs: f32) -> Self::Output {
        Self::new(self.x - rhs, self.y - rhs, self.z - rhs)
    }
}

impl SubAssign<f32> for Vec3 {
    /// Subtracts `rhs` from each component of `self`.
    #[inline]
    fn sub_assign(&mut self, rhs: f32) {
        self.x -= rhs;
        self.y -= rhs;
        self.z -= rhs;
    }
}

impl Mul for Vec3 {
    type Output = Self;

    /// Returns a `Vec3` with the coresponding components of `self`
    /// multiplied by `rhs`.
    #[inline]
    fn mul(self, rhs: Self) -> Self::Output {
        Self::new(self.x * rhs.x, self.y * rhs.y, self.z * rhs.z)
    }
}

impl MulAssign for Vec3 {
    /// Multiplies the corresponding components of `self` by `rhs`.
    #[inline]
    fn mul_assign(&mut self, rhs: Self) {
        self.x *= rhs.x;
        self.y *= rhs.y;
        self.z *= rhs.z;
    }
}

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

    /// Returns a `Vec3` with each component of `self`
    /// multiplied by `rhs`.
    #[inline]
    fn mul(self, rhs: f32) -> Self::Output {
        Self::new(self.x * rhs, self.y * rhs, self.z * rhs)
    }
}

impl MulAssign<f32> for Vec3 {
    /// Multiplies each component of `self` by `rhs`.
    #[inline]
    fn mul_assign(&mut self, rhs: f32) {
        self.x *= rhs;
        self.y *= rhs;
        self.z *= rhs;
    }
}

impl Div for Vec3 {
    type Output = Self;

    /// Returns a `Vec3` with the coresponding components of `self`
    /// divided by `rhs`.
    #[inline]
    fn div(self, rhs: Self) -> Self::Output {
        Self::new(self.x / rhs.x, self.y / rhs.y, self.z / rhs.z)
    }
}

impl DivAssign for Vec3 {
    /// Divides the corresponding components of `self` by `rhs`.
    #[inline]
    fn div_assign(&mut self, rhs: Self) {
        self.x /= rhs.x;
        self.y /= rhs.y;
        self.z /= rhs.z;
    }
}

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

    /// Returns a `Vec3` with each component of `self`
    /// divided by `rhs`.
    #[inline]
    fn div(self, rhs: f32) -> Self::Output {
        Self::new(self.x / rhs, self.y / rhs, self.z / rhs)
    }
}

impl DivAssign<f32> for Vec3 {
    /// Divides each component of `self` by `rhs`.
    #[inline]
    fn div_assign(&mut self, rhs: f32) {
        self.x /= rhs;
        self.y /= rhs;
        self.z /= rhs;
    }
}

impl Rem for Vec3 {
    type Output = Self;

    /// Returns a `Vec3` with the remainder of dividing corresponding components
    /// of `self` by `rhs`.
    #[inline]
    fn rem(self, rhs: Self) -> Self::Output {
        Self::new(self.x % rhs.x, self.y % rhs.y, self.z % rhs.z)
    }
}

impl RemAssign for Vec3 {
    /// Sets each component of `self` to the remainder of dividing it by
    /// the corresponding component of `rhs`.
    #[inline]
    fn rem_assign(&mut self, rhs: Self) {
        self.x %= rhs.x;
        self.y %= rhs.y;
        self.z %= rhs.z;
    }
}

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

    /// Returns a `Vec3` with the remainder of dividing each component
    /// of `self` by `rhs`.
    #[inline]
    fn rem(self, rhs: f32) -> Self::Output {
        Self::new(self.x % rhs, self.y % rhs, self.z % rhs)
    }
}

impl RemAssign<f32> for Vec3 {
    /// Sets each component of `self` to the remainder of dividing it by `rhs`.
    #[inline]
    fn rem_assign(&mut self, rhs: f32) {
        self.x %= rhs;
        self.y %= rhs;
        self.z %= rhs;
    }
}

impl Neg for Vec3 {
    type Output = Self;

    /// Negates all components of `self`.
    #[inline]
    fn neg(self) -> Self::Output {
        Self::new(-self.x, -self.y, -self.z)
    }
}

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`.
    ///
    /// # Panics
    /// Panics if `index` is greater than `2`.
    #[inline]
    fn index(&self, index: usize) -> &Self::Output {
        match index {
            0 => &self.x,
            1 => &self.y,
            2 => &self.z,
            _ => panic!("index out of bounds"),
        }
    }
}

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`.
    ///
    /// # Panics
    /// Panics if `index` is greater than `2`.
    #[inline]
    fn index_mut(&mut self, index: usize) -> &mut Self::Output {
        match index {
            0 => &mut self.x,
            1 => &mut self.y,
            2 => &mut self.z,
            _ => panic!("index out of bounds"),
        }
    }
}

impl AsRef<[f32; 3]> for Vec3 {
    /// Returns a `&[f32; 3]` reference to the `Vec3` components.
    /// Elements map to `[x, y, z]`.
    #[inline]
    fn as_ref(&self) -> &[f32; 3] {
        unsafe { &*(self as *const Vec3 as *const [f32; 3]) }
    }
}

impl AsMut<[f32; 3]> for Vec3 {
    /// Returns a `&[f32; 3]` mutable reference to the `Vec3` components.
    /// Elements map to `[x, y, z]`.
    #[inline]
    fn as_mut(&mut self) -> &mut [f32; 3] {
        unsafe { &mut *(self as *mut Vec3 as *mut [f32; 3]) }
    }
}

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 From<[f32; 3]> for Vec3 {
    /// Creates a `Vec3` from a `[f32; 3]`.
    /// Elements map to `(x, y, z)`.
    #[inline]
    fn from(v: [f32; 3]) -> Self {
        Self::new(v[0], v[1], v[2])
    }
}

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

impl From<&[f32]> for Vec3 {
    /// Creates a `Vec3` from a `&[f32]`.
    /// First 3 elements map to `(x, y, z)`.
    ///
    /// # Panics
    /// Panics if `v` is less than 3 elements long.
    #[inline]
    fn from(v: &[f32]) -> Self {
        Self::new(v[0], v[1], v[2])
    }
}

impl From<Vec2> for Vec3 {
    /// Creates a `Vec3` from a `Vec2`.
    /// Elements map to `(x, y, 0.0)`.
    #[inline]
    fn from(v: Vec2) -> Self {
        Self::new(v.x, v.y, 0.0)
    }
}

impl From<Vec4> for Vec3 {
    /// Creates a `Vec3` from a `Vec4`.
    /// Elements map to `(x, y, z)`, `w` is discarded.
    #[inline]
    fn from(v: Vec4) -> Self {
        Self::new(v.x, v.y, v.z)
    }
}

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