//! Three-dimensional vector with named components.

use core::ops::{Add, Mul, Sub};

/// A three-component vector.  Used for position and velocity in any
/// coordinate frame.  All access is through named fields, avoiding
/// array indexing entirely.
#[derive(Debug, Clone, Copy, PartialEq)]
pub struct Vec3 {
    x: f64,
    y: f64,
    z: f64,
}

impl Vec3 {
    #[must_use]
    pub fn new(x: f64, y: f64, z: f64) -> Self {
        Self { x, y, z }
    }

    #[must_use]
    pub fn x(self) -> f64 {
        self.x
    }

    #[must_use]
    pub fn y(self) -> f64 {
        self.y
    }

    #[must_use]
    pub fn z(self) -> f64 {
        self.z
    }

    /// Euclidean magnitude.
    #[must_use]
    pub fn magnitude(self) -> f64 {
        f64::sqrt(self.x * self.x + self.y * self.y + self.z * self.z)
    }

    /// Scale each component by a constant factor.
    #[must_use]
    pub fn scale(self, s: f64) -> Self {
        Self {
            x: self.x * s,
            y: self.y * s,
            z: self.z * s,
        }
    }
}

impl Add for Vec3 {
    type Output = Self;

    fn add(self, rhs: Self) -> Self {
        Self {
            x: self.x + rhs.x,
            y: self.y + rhs.y,
            z: self.z + rhs.z,
        }
    }
}

impl Sub for Vec3 {
    type Output = Self;

    fn sub(self, rhs: Self) -> Self {
        Self {
            x: self.x - rhs.x,
            y: self.y - rhs.y,
            z: self.z - rhs.z,
        }
    }
}

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

    fn mul(self, rhs: f64) -> Self {
        self.scale(rhs)
    }
}
