ndimpoint 0.1.2

A library for working with N-dimensional points in Rust.
Documentation
use std::ops::{Add, Div, Mul, Sub};

#[derive(Debug, Clone)]
pub struct Point<T> {
    p: Vec<T>,
}

impl<T> Point<T>
where
    T: Into<f64> + Copy, // Ensures T can be converted to f64
{
    pub fn new(p: Vec<T>) -> Self {
        Point { p }
    }

    pub fn dim(&self) -> usize {
        self.p.len()
    }

    pub fn dist(&self) -> f64 {
        self.p.iter().map(|&x| x.into().powi(2)).sum::<f64>().sqrt()
    }

    pub fn apply(&self, func: fn(&[T]) -> f64) -> f64 {
        func(&self.p)
    }
}
impl<T> Add<&Point<T>> for &Point<T>
where
    T: Add<Output = T> + Copy,
{
    type Output = Point<T>;

    fn add(self, other: &Point<T>) -> Self::Output {
        let p = self
            .p
            .iter()
            .zip(other.p.iter())
            .map(|(&a, &b)| a + b)
            .collect();
        Point { p }
    }
}

impl<T> Sub<&Point<T>> for &Point<T>
where
    T: Sub<Output = T> + Copy,
{
    type Output = Point<T>;

    fn sub(self, other: &Point<T>) -> Self::Output {
        let p = self
            .p
            .iter()
            .zip(other.p.iter())
            .map(|(&a, &b)| a - b)
            .collect();
        Point { p }
    }
}

impl<T> Mul<&Point<T>> for &Point<T>
where
    T: Mul<Output = T> + Copy,
{
    type Output = Point<T>;

    fn mul(self, other: &Point<T>) -> Self::Output {
        let p = self
            .p
            .iter()
            .zip(other.p.iter())
            .map(|(&a, &b)| a * b)
            .collect();
        Point { p }
    }
}

impl<T> Add<T> for &Point<T>
where
    T: Add<Output = T> + Copy,
{
    type Output = Point<T>;

    fn add(self, scalar: T) -> Self::Output {
        let p = self.p.iter().map(|&a| a + scalar).collect();
        Point { p }
    }
}

impl<T> Sub<T> for &Point<T>
where
    T: Sub<Output = T> + Copy,
{
    type Output = Point<T>;

    fn sub(self, scalar: T) -> Self::Output {
        let p = self.p.iter().map(|&a| a - scalar).collect();
        Point { p }
    }
}

impl<T> Mul<T> for &Point<T>
where
    T: Mul<Output = T> + Copy,
{
    type Output = Point<T>;

    fn mul(self, scalar: T) -> Self::Output {
        let p = self.p.iter().map(|&a| a * scalar).collect();
        Point { p }
    }
}

impl<T> Div<T> for &Point<T>
where
    T: Div<Output = T> + Copy,
{
    type Output = Point<T>;

    fn div(self, scalar: T) -> Self::Output {
        let p = self.p.iter().map(|&a| a / scalar).collect();
        Point { p }
    }
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn new() {
        let ivec: Vec<i32> = vec![1, 2, 3];
        let fvec: Vec<f64> = vec![1.0, 2.0, 3.0];

        let iv = Point::new(ivec.clone());
        let fv = Point::new(fvec.clone());
        assert_eq!(iv.p, ivec);
        assert_eq!(fv.p, fvec);
        dbg!(iv);
    }

    #[test]
    fn add() {
        let iv1 = Point::new(vec![1, 2, 3]);
        let iv2 = Point::new(vec![4, 5, 6]);
        let iv3 = &iv1 + &iv2;
        assert_eq!(iv3.p, vec![5, 7, 9]);
    }

    #[test]
    fn sub() {
        let iv1 = Point::new(vec![1, 2, 3]);
        let iv2 = Point::new(vec![4, 5, 6]);
        let iv3 = &iv1 - &iv2;
        assert_eq!(iv3.p, vec![-3, -3, -3]);
    }

    #[test]
    fn mul() {
        let iv1 = Point::new(vec![1, 2, 3]);
        let iv2 = Point::new(vec![4, 5, 6]);
        let iv3 = &iv1 * &iv2;
        assert_eq!(iv3.p, vec![4, 10, 18]);
    }

    #[test]
    fn scalar_add() {
        let iv1 = Point::new(vec![1, 2, 3]);
        let iv2 = &iv1 + 10;
        let iv3 = &iv1 + 20;
        assert_eq!(iv2.p, vec![11, 12, 13]);
    }

    #[test]
    fn scalar_sub() {
        let iv1 = Point::new(vec![1, 2, 3]);
        let iv2 = &iv1 - 10;
        let iv3 = &iv1 - 20;
        assert_eq!(iv2.p, vec![-9, -8, -7]);
    }

    #[test]
    fn scalar_mul() {
        let iv1 = Point::new(vec![1, 2, 3]);
        let iv2 = &iv1 * 10;
        let iv3 = &iv1 * 20;
        assert_eq!(iv2.p, vec![10, 20, 30]);
    }

    #[test]
    fn scalar_div() {
        let iv1 = Point::new(vec![10, 20, 30]);
        let iv2 = &iv1 / 10;
        let iv3 = &iv1 / 20;
        assert_eq!(iv2.p, vec![1, 2, 3]);
    }

    #[test]
    fn dim() {
        let iv1 = Point::new(vec![1, 2, 3]);
        let iv2 = Point::new(vec![4, 5, 6, 7]);
        assert_eq!(iv1.dim(), 3);
        assert_eq!(iv2.dim(), 4);
    }

    #[test]
    fn dist() {
        let iv1 = Point::new(vec![1, 2, 3]);
        assert_eq!(iv1.dist(), (14.0_f64).sqrt());
    }

    #[test]
    fn apply() {
        let iv1 = Point::new(vec![1, 2, 3]);
        let iv2 = iv1.apply(|x| x[0] as f64 + x[1] as f64 + x[2] as f64);
        assert_eq!(iv2, 6.0);
    }
}