mathguru 0.2.0

An algebra system capable of mixed numeric and symbolic computation.
Documentation
use array_init::array_init;
use num_traits::Zero;
use std::fmt;
use std::ops::{Add, AddAssign, Mul, MulAssign, Neg, Sub, SubAssign};

pub type Vector3<T> = Vector<T, 3>;

#[derive(Debug, Clone, PartialEq, Eq)]
pub struct Vector<T, const D: usize> {
    pub data: [T; D],
}

impl<T: AddAssign, const D: usize> Add for Vector<T, D> {
    type Output = Self;

    fn add(self, rhs: Self) -> Self::Output {
        let mut data = self.data;
        for (i, value) in rhs.data.into_iter().enumerate() {
            data[i] += value;
        }
        Self { data }
    }
}

impl<T: AddAssign + Clone, const D: usize> Add for &Vector<T, D> {
    type Output = Vector<T, D>;

    fn add(self, rhs: Self) -> Self::Output {
        let mut data = self.data.clone();
        for (i, value) in rhs.data.iter().enumerate() {
            data[i] += value.clone();
        }
        Vector { data }
    }
}

impl<T: SubAssign, const D: usize> Sub for Vector<T, D> {
    type Output = Self;

    fn sub(self, rhs: Self) -> Self::Output {
        let mut data = self.data;
        for (i, value) in rhs.data.into_iter().enumerate() {
            data[i] -= value;
        }
        Self { data }
    }
}

impl<T: SubAssign + Clone, const D: usize> Sub for &Vector<T, D> {
    type Output = Vector<T, D>;

    fn sub(self, rhs: Self) -> Self::Output {
        let mut data = self.data.clone();
        for (i, value) in rhs.data.iter().enumerate() {
            data[i] -= value.clone();
        }
        Vector { data }
    }
}

impl<T: MulAssign + Clone, const D: usize> Mul<T> for Vector<T, D> {
    type Output = Vector<T, D>;

    fn mul(self, rhs: T) -> Self::Output {
        let mut data = self.data;
        for i in 0..D {
            data[i] *= rhs.clone();
        }
        Vector { data }
    }
}

impl<T: MulAssign + Clone, const D: usize> Mul<T> for &Vector<T, D> {
    type Output = Vector<T, D>;

    fn mul(self, rhs: T) -> Self::Output {
        let mut data = self.data.clone();
        for i in 0..D {
            data[i] *= rhs.clone();
        }
        Vector { data }
    }
}

impl<T: Neg<Output = T> + Clone, const D: usize> Neg for Vector<T, D> {
    type Output = Vector<T, D>;

    fn neg(self) -> Self::Output {
        let mut data = self.data;
        for i in 0..D {
            data[i] = -data[i].clone();
        }
        Vector { data }
    }
}

impl<T: Neg<Output = T> + Clone, const D: usize> Neg for &Vector<T, D> {
    type Output = Vector<T, D>;

    fn neg(self) -> Self::Output {
        let mut data = self.data.clone();
        for i in 0..D {
            data[i] = -data[i].clone();
        }
        Vector { data }
    }
}

impl<T: Zero + AddAssign, const D: usize> Zero for Vector<T, D> {
    fn zero() -> Self {
        Vector {
            data: array_init(|_| T::zero()),
        }
    }

    fn is_zero(&self) -> bool {
        self.data.iter().all(|v| v.is_zero())
    }
}

impl<T: Mul<Output = T> + AddAssign + Zero + Clone, const D: usize> Vector<T, D> {
    pub fn dot(&self, other: &Vector<T, D>) -> T {
        let mut sum = T::zero();

        for (a, b) in self.data.iter().zip(other.data.iter()) {
            sum += a.clone() * b.clone();
        }

        sum
    }
}

impl<T: Clone> Vector3<T> {
    pub fn new(x: T, y: T, z: T) -> Self {
        Vector { data: [x, y, z] }
    }
    pub fn x(&self) -> T {
        self.data[0].clone()
    }
    pub fn y(&self) -> T {
        self.data[1].clone()
    }
    pub fn z(&self) -> T {
        self.data[2].clone()
    }
}

impl<T: Mul<Output = T> + Sub<Output = T> + Clone> Vector3<T> {
    pub fn cross(&self, rhs: &Vector3<T>) -> Vector3<T> {
        Self {
            data: [
                self.y() * rhs.z() - rhs.y() * self.z(),
                self.z() * rhs.x() - rhs.z() * self.x(),
                self.x() * rhs.y() - rhs.x() * self.y(),
            ],
        }
    }
}

impl<T: Clone> Vector<T, 2> {
    pub fn new(x: T, y: T) -> Self {
        Vector { data: [x, y] }
    }
    pub fn x(&self) -> T {
        self.data[0].clone()
    }
    pub fn y(&self) -> T {
        self.data[1].clone()
    }
}

impl<T: Clone> Vector<T, 4> {
    pub fn new(x: T, y: T, z: T, w: T) -> Self {
        Vector { data: [x, y, z, w] }
    }
    pub fn x(&self) -> T {
        self.data[0].clone()
    }
    pub fn y(&self) -> T {
        self.data[1].clone()
    }
    pub fn z(&self) -> T {
        self.data[2].clone()
    }
    pub fn w(&self) -> T {
        self.data[3].clone()
    }
}

impl<T: fmt::Display, const D: usize> fmt::Display for Vector<T, D> {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        write!(f, "(")?;
        let mut first = true;
        for value in &self.data {
            if first {
                first = false;
            } else {
                write!(f, ", ")?;
            }
            write!(f, "{}", value)?;
        }
        write!(f, ")")?;
        Ok(())
    }
}