linmath 0.0.2

A linear algebra and mathematics library for computer graphics.
Documentation
use approx::{AbsDiffEq, RelativeEq, UlpsEq};
use num_traits::Float;
use std::ops::{Add, AddAssign, Mul, MulAssign, Sub, SubAssign};

macro_rules! sum {
    ($h:expr) => ($h);
    ($h:expr, $($t:expr),*) => ($h + sum!($($t),*));
}

macro_rules! generate_vector_n {
    ($VectorN: ident, $($field: ident),+) => {
        #[repr(C)]
        #[derive(Copy, Clone, Debug, PartialEq)]
        pub struct $VectorN<T: Float> {
            $(pub $field: T),+
        }

        impl<T: Float> $VectorN<T> {
            #[inline]
            pub fn new($($field: T),+) -> $VectorN<T> {
                $VectorN { $($field: $field),+ }
            }

            #[inline]
            fn add_vector_and_vector(a: &$VectorN<T>, b: &$VectorN<T>) -> $VectorN<T> {
                $VectorN::new($(a.$field + b.$field),+)
            }

            #[inline]
            fn sub_vector_and_vector(a: &$VectorN<T>, b: &$VectorN<T>) -> $VectorN<T> {
                $VectorN::new($(a.$field - b.$field),+)
            }

            #[inline]
            fn mul_vector_and_scalar(a: &$VectorN<T>, b: &T) -> $VectorN<T> {
                $VectorN::new($(a.$field * *b),+)
            }

            #[inline]
            pub fn dot(a: &$VectorN<T>, b: &$VectorN<T>) -> T {
                sum!($(a.$field * b.$field),+)
            }

            #[inline]
            pub fn length(v: &$VectorN<T>) -> T {
                $VectorN::dot(v, v).sqrt()
            }

            #[inline]
            pub fn normalize(v: &$VectorN<T>) -> $VectorN<T> {
                *v * (T::one() / $VectorN::length(v))
            }
        }

        impl<T: Float> Add<$VectorN<T>> for $VectorN<T> {
            type Output = $VectorN<T>;

            #[inline]
            fn add(self, rhs: $VectorN<T>) -> Self::Output {
                $VectorN::add_vector_and_vector(&self, &rhs)
            }
        }

        impl<T: Float> Sub<$VectorN<T>> for $VectorN<T> {
            type Output = $VectorN<T>;

            #[inline]
            fn sub(self, rhs: $VectorN<T>) -> Self::Output {
                $VectorN::sub_vector_and_vector(&self, &rhs)
            }
        }

        impl<T: Float> Mul<T> for $VectorN<T> {
            type Output = $VectorN<T>;

            #[inline]
            fn mul(self, rhs: T) -> Self::Output {
                $VectorN::mul_vector_and_scalar(&self, &rhs)
            }
        }

        impl<T: Float> AddAssign<$VectorN<T>> for $VectorN<T> {
            #[inline]
            fn add_assign(&mut self, rhs: $VectorN<T>) {
                *self = $VectorN::add_vector_and_vector(self, &rhs)
            }
        }

        impl<T: Float> SubAssign<$VectorN<T>> for $VectorN<T> {
            #[inline]
            fn sub_assign(&mut self, rhs: $VectorN<T>) {
                *self = $VectorN::sub_vector_and_vector(self, &rhs)
            }
        }

        impl<T: Float> MulAssign<T> for $VectorN<T> {
            #[inline]
            fn mul_assign(&mut self, rhs: T) {
                *self = $VectorN::mul_vector_and_scalar(self, &rhs)
            }
        }

        impl<T: AbsDiffEq> AbsDiffEq for $VectorN<T> where
            T::Epsilon: Copy,
            T: Float,
        {
            type Epsilon = T::Epsilon;

            #[inline]
            fn default_epsilon() -> T::Epsilon {
                T::default_epsilon()
            }

            #[inline]
            fn abs_diff_eq(&self, other: &Self, epsilon: T::Epsilon) -> bool {
                $(T::abs_diff_eq(&self.$field, &other.$field, epsilon))&&+
            }
        }

        impl<T: RelativeEq> RelativeEq for $VectorN<T> where
            T::Epsilon: Copy,
            T: Float,
        {
            #[inline]
            fn default_max_relative() -> T::Epsilon {
                T::default_max_relative()
            }

            #[inline]
            fn relative_eq(&self, other: &Self, epsilon: T::Epsilon, max_relative: T::Epsilon) -> bool {
                $(T::relative_eq(&self.$field, &other.$field, epsilon, max_relative))&&+
            }
        }

        impl<T: UlpsEq> UlpsEq for $VectorN<T> where
            T::Epsilon: Copy,
            T: Float,
        {
            #[inline]
            fn default_max_ulps() -> u32 {
                T::default_max_ulps()
            }

            #[inline]
            fn ulps_eq(&self, other: &Self, epsilon: T::Epsilon, max_ulps: u32) -> bool {
                $(T::ulps_eq(&self.$field, &other.$field, epsilon, max_ulps))&&+
            }
        }
    };
}

generate_vector_n!(Vector2, x, y);
generate_vector_n!(Vector3, x, y, z);
generate_vector_n!(Vector4, x, y, z, w);

impl<T: Float> Vector3<T> {
    #[inline]
    pub fn cross(a: &Vector3<T>, b: &Vector3<T>) -> Vector3<T> {
        Vector3::new(
            a.y * b.z - a.z * b.y,
            a.z * b.x - a.x * b.z,
            a.x * b.y - a.y * b.x,
        )
    }
}

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

    #[test]
    fn vector2_add() {
        let a = Vector2::new(1.0, 2.0);
        let b = Vector2::new(3.0, 4.0);
        assert_eq!(a + b, Vector2::new(4.0, 6.0));
    }

    #[test]
    fn vector2_add_assign() {
        let mut a = Vector2::new(1.0, 2.0);
        let b = Vector2::new(3.0, 4.0);
        a += b;
        assert_eq!(a, Vector2::new(4.0, 6.0));
    }

    #[test]
    fn vector2_sub() {
        let a = Vector2::new(1.0, 2.0);
        let b = Vector2::new(3.0, 4.0);
        assert_eq!(a - b, Vector2::new(-2.0, -2.0));
    }

    #[test]
    fn vector2_sub_assign() {
        let mut a = Vector2::new(1.0, 2.0);
        let b = Vector2::new(3.0, 4.0);
        a -= b;
        assert_eq!(a, Vector2::new(-2.0, -2.0));
    }

    #[test]
    fn vector2_mul() {
        let v = Vector2::new(1.0, 2.0);
        assert_eq!(v * 2.0, Vector2::new(2.0, 4.0));
    }

    #[test]
    fn vector2_mul_assign() {
        let mut v = Vector2::new(1.0, 2.0);
        v *= 2.0;
        assert_eq!(v, Vector2::new(2.0, 4.0));
    }

    #[test]
    fn vector2_dot() {
        let a = Vector2::new(1.0, 2.0);
        let b = Vector2::new(3.0, 4.0);
        assert_eq!(Vector2::dot(&a, &b), 11.0);
    }

    #[test]
    fn vector2_length() {
        let v = Vector2::new(1.0, 0.0);
        assert_eq!(Vector2::length(&v), 1.0);
    }

    #[test]
    fn vector2_normalize() {
        let v = Vector2::new(2.0, 0.0);
        assert_eq!(Vector2::normalize(&v), Vector2::new(1.0, 0.0))
    }

    #[test]
    fn vector3_add() {
        let a = Vector3::new(1.0, 2.0, 3.0);
        let b = Vector3::new(4.0, 5.0, 6.0);
        assert_eq!(a + b, Vector3::new(5.0, 7.0, 9.0));
    }

    #[test]
    fn vector3_add_assign() {
        let mut a = Vector3::new(1.0, 2.0, 3.0);
        let b = Vector3::new(4.0, 5.0, 6.0);
        a += b;
        assert_eq!(a, Vector3::new(5.0, 7.0, 9.0));
    }

    #[test]
    fn vector3_sub() {
        let a = Vector3::new(1.0, 2.0, 3.0);
        let b = Vector3::new(4.0, 5.0, 6.0);
        assert_eq!(a - b, Vector3::new(-3.0, -3.0, -3.0));
    }

    #[test]
    fn vector3_sub_assign() {
        let mut a = Vector3::new(1.0, 2.0, 3.0);
        let b = Vector3::new(4.0, 5.0, 6.0);
        a -= b;
        assert_eq!(a, Vector3::new(-3.0, -3.0, -3.0));
    }

    #[test]
    fn vector3_mul() {
        let v = Vector3::new(1.0, 2.0, 3.0);
        assert_eq!(v * 2.0, Vector3::new(2.0, 4.0, 6.0));
    }

    #[test]
    fn vector3_mul_assign() {
        let mut v = Vector3::new(1.0, 2.0, 3.0);
        v *= 2.0;
        assert_eq!(v, Vector3::new(2.0, 4.0, 6.0));
    }

    #[test]
    fn vector3_dot() {
        let a = Vector3::new(1.0, 2.0, 3.0);
        let b = Vector3::new(4.0, 5.0, 6.0);
        assert_eq!(Vector3::dot(&a, &b), 32.0);
    }

    #[test]
    fn vector3_length() {
        let v = Vector3::new(1.0, 0.0, 0.0);
        assert_eq!(Vector3::length(&v), 1.0);
    }

    #[test]
    fn vector3_normalize() {
        let v = Vector3::new(2.0, 0.0, 0.0);
        assert_eq!(Vector3::normalize(&v), Vector3::new(1.0, 0.0, 0.0))
    }

    #[test]
    fn vector3_cross() {
        let a = Vector3::new(1.0, 2.0, 3.0);
        let b = Vector3::new(4.0, 5.0, 6.0);
        assert_eq!(Vector3::cross(&a, &b), Vector3::new(-3.0, 6.0, -3.0));
    }

    #[test]
    fn vector4_add() {
        let a = Vector4::new(1.0, 2.0, 3.0, 4.0);
        let b = Vector4::new(5.0, 6.0, 7.0, 8.0);
        assert_eq!(a + b, Vector4::new(6.0, 8.0, 10.0, 12.0));
    }

    #[test]
    fn vector4_add_assign() {
        let mut a = Vector4::new(1.0, 2.0, 3.0, 4.0);
        let b = Vector4::new(5.0, 6.0, 7.0, 8.0);
        a += b;
        assert_eq!(a, Vector4::new(6.0, 8.0, 10.0, 12.0));
    }

    #[test]
    fn vector4_sub() {
        let a = Vector4::new(1.0, 2.0, 3.0, 4.0);
        let b = Vector4::new(5.0, 6.0, 7.0, 8.0);
        assert_eq!(a - b, Vector4::new(-4.0, -4.0, -4.0, -4.0));
    }

    #[test]
    fn vector4_sub_assign() {
        let mut a = Vector4::new(1.0, 2.0, 3.0, 4.0);
        let b = Vector4::new(5.0, 6.0, 7.0, 8.0);
        a -= b;
        assert_eq!(a, Vector4::new(-4.0, -4.0, -4.0, -4.0));
    }

    #[test]
    fn vector4_mul() {
        let v = Vector4::new(1.0, 2.0, 3.0, 4.0);
        assert_eq!(v * 2.0, Vector4::new(2.0, 4.0, 6.0, 8.0));
    }

    #[test]
    fn vector4_mul_assign() {
        let mut v = Vector4::new(1.0, 2.0, 3.0, 4.0);
        v *= 2.0;
        assert_eq!(v, Vector4::new(2.0, 4.0, 6.0, 8.0));
    }

    #[test]
    fn vector4_dot() {
        let a = Vector4::new(1.0, 2.0, 3.0, 4.0);
        let b = Vector4::new(5.0, 6.0, 7.0, 8.0);
        assert_eq!(Vector4::dot(&a, &b), 70.0);
    }

    #[test]
    fn vector4_length() {
        let v = Vector4::new(1.0, 0.0, 0.0, 0.0);
        assert_eq!(Vector4::length(&v), 1.0);
    }

    #[test]
    fn vector4_normalize() {
        let v = Vector4::new(2.0, 0.0, 0.0, 0.0);
        assert_eq!(Vector4::normalize(&v), Vector4::new(1.0, 0.0, 0.0, 0.0))
    }
}