Repository: bitshifter/glam-rs
Pull request #93 (2020-11-09 21:01:10)

Implement arithmetic traits
This PR implements the arithmetic traits `Sum` and `Product`, allowing you to do this stuff:
```rust
let vecs: Vec<Vec2> = vec![Vec2::new(1.0, 2.0), Vec2::new(3.0, 4.0)];

assert_eq!(v.iter().sum::<Vec2>(), Vec2::new(4.0, 6.0));
```

Apologies for the PR spam, I messed up the last PR.


Patch:
diff --git a/src/f32/mat2.rs b/src/f32/mat2.rs
index c86bf80..6f24d6c 100644
--- a/src/f32/mat2.rs
+++ b/src/f32/mat2.rs
@@ -8,6 +8,9 @@ use core::{
     ops::{Add, Mul, Sub},
 };
 
+#[cfg(feature = "std")]
+use std::iter::{Product, Sum};
+
 const ZERO: Mat2 = const_mat2!([0.0; 4]);
 const IDENTITY: Mat2 = const_mat2!([1.0, 0.0], [0.0, 1.0]);
 
@@ -359,3 +362,23 @@ impl Mul<f32> for Mat2 {
         self.mul_scalar(other)
     }
 }
+
+#[cfg(feature = "std")]
+impl<'a> Sum<&'a Self> for Mat2 {
+    fn sum<I>(iter: I) -> Self
+    where
+        I: Iterator<Item = &'a Self>,
+    {
+        iter.fold(ZERO, |a, &b| Self::add(a, b))
+    }
+}
+
+#[cfg(feature = "std")]
+impl<'a> Product<&'a Self> for Mat2 {
+    fn product<I>(iter: I) -> Self
+    where
+        I: Iterator<Item = &'a Self>,
+    {
+        iter.fold(IDENTITY, |a, &b| Self::mul(a, b))
+    }
+}
\ No newline at end of file
diff --git a/src/f32/mat3.rs b/src/f32/mat3.rs
index fea8710..56211b7 100644
--- a/src/f32/mat3.rs
+++ b/src/f32/mat3.rs
@@ -4,6 +4,9 @@ use core::{
     ops::{Add, Mul, Sub},
 };
 
+#[cfg(feature = "std")]
+use std::iter::{Product, Sum};
+
 const ZERO: Mat3 = const_mat3!([0.0; 9]);
 const IDENTITY: Mat3 = const_mat3!([1.0, 0.0, 0.0], [0.0, 1.0, 0.0], [0.0, 0.0, 1.0]);
 
@@ -520,3 +523,23 @@ impl Mul<f32> for Mat3 {
         self.mul_scalar(other)
     }
 }
+
+#[cfg(feature = "std")]
+impl<'a> Sum<&'a Self> for Mat3 {
+    fn sum<I>(iter: I) -> Self
+    where
+        I: Iterator<Item = &'a Self>,
+    {
+        iter.fold(ZERO, |a, &b| Self::add(a, b))
+    }
+}
+
+#[cfg(feature = "std")]
+impl<'a> Product<&'a Self> for Mat3 {
+    fn product<I>(iter: I) -> Self
+    where
+        I: Iterator<Item = &'a Self>,
+    {
+        iter.fold(IDENTITY, |a, &b| Self::mul(a, b))
+    }
+}
\ No newline at end of file
diff --git a/src/f32/mat4.rs b/src/f32/mat4.rs
index dea111d..dd45ffc 100644
--- a/src/f32/mat4.rs
+++ b/src/f32/mat4.rs
@@ -8,6 +8,9 @@ use core::{
     ops::{Add, Mul, Sub},
 };
 
+#[cfg(feature = "std")]
+use std::iter::{Product, Sum};
+
 const ZERO: Mat4 = const_mat4!([0.0; 16]);
 const IDENTITY: Mat4 = const_mat4!(
     [1.0, 0.0, 0.0, 0.0],
@@ -1132,3 +1135,23 @@ impl Mul<f32> for Mat4 {
         self.mul_scalar(other)
     }
 }
+
+#[cfg(feature = "std")]
+impl<'a> Sum<&'a Self> for Mat4 {
+    fn sum<I>(iter: I) -> Self
+    where
+        I: Iterator<Item = &'a Self>,
+    {
+        iter.fold(ZERO, |a, &b| Self::add(a, b))
+    }
+}
+
+#[cfg(feature = "std")]
+impl<'a> Product<&'a Self> for Mat4 {
+    fn product<I>(iter: I) -> Self
+    where
+        I: Iterator<Item = &'a Self>,
+    {
+        iter.fold(IDENTITY, |a, &b| Self::mul(a, b))
+    }
+}
\ No newline at end of file
diff --git a/src/f32/quat.rs b/src/f32/quat.rs
index cd57513..1212572 100644
--- a/src/f32/quat.rs
+++ b/src/f32/quat.rs
@@ -9,6 +9,10 @@ use core::{
     ops::{Add, Div, Mul, MulAssign, Neg, Sub},
 };
 
+#[cfg(feature = "std")]
+use std::iter::{Product, Sum};
+
+const ZERO: Quat = const_quat!([0.0, 0.0, 0.0, 0.0]);
 const IDENTITY: Quat = const_quat!([0.0, 0.0, 0.0, 1.0]);
 
 /// A quaternion representing an orientation.
@@ -725,3 +729,23 @@ impl From<__m128> for Quat {
         Self(Vec4(t))
     }
 }
+
+#[cfg(feature = "std")]
+impl<'a> Sum<&'a Self> for Quat {
+    fn sum<I>(iter: I) -> Self
+    where
+        I: Iterator<Item = &'a Self>,
+    {
+        iter.fold(ZERO, |a, &b| Self::add(a, b))
+    }
+}
+
+#[cfg(feature = "std")]
+impl<'a> Product<&'a Self> for Quat {
+    fn product<I>(iter: I) -> Self
+    where
+        I: Iterator<Item = &'a Self>,
+    {
+        iter.fold(IDENTITY, |a, &b| Self::mul(a, b))
+    }
+}
\ No newline at end of file
diff --git a/src/f32/vec2.rs b/src/f32/vec2.rs
index 0f03125..76f91ed 100644
--- a/src/f32/vec2.rs
+++ b/src/f32/vec2.rs
@@ -1,6 +1,9 @@
 use crate::f32::{Vec2Mask, Vec3};
 use core::{f32, fmt, ops::*};
 
+#[cfg(feature = "std")]
+use std::iter::{Product, Sum};
+
 const ZERO: Vec2 = const_vec2!([0.0; 2]);
 const ONE: Vec2 = const_vec2!([1.0; 2]);
 const X_AXIS: Vec2 = const_vec2!([1.0, 0.0]);
@@ -563,3 +566,23 @@ impl From<Vec2> for [f32; 2] {
         [v.0, v.1]
     }
 }
+
+#[cfg(feature = "std")]
+impl<'a> Sum<&'a Self> for Vec2 {
+    fn sum<I>(iter: I) -> Self
+    where
+        I: Iterator<Item = &'a Self>,
+    {
+        iter.fold(ZERO, |a, &b| Self::add(a, b))
+    }
+}
+
+#[cfg(feature = "std")]
+impl<'a> Product<&'a Self> for Vec2 {
+    fn product<I>(iter: I) -> Self
+    where
+        I: Iterator<Item = &'a Self>,
+    {
+        iter.fold(ONE, |a, &b| Self::mul(a, b))
+    }
+}
diff --git a/src/f32/vec3.rs b/src/f32/vec3.rs
index 3978baa..3fe2411 100644
--- a/src/f32/vec3.rs
+++ b/src/f32/vec3.rs
@@ -1,6 +1,9 @@
 use super::{Vec2, Vec3A, Vec3Mask, Vec4};
 use core::{fmt, ops::*};
 
+#[cfg(feature = "std")]
+use std::iter::{Product, Sum};
+
 const ZERO: Vec3 = const_vec3!([0.0; 3]);
 const ONE: Vec3 = const_vec3!([1.0; 3]);
 const X_AXIS: Vec3 = const_vec3!([1.0, 0.0, 0.0]);
@@ -683,3 +686,23 @@ fn test_vec3_private() {
         vec3(-0.5, 1.0, -5.0)
     );
 }
+
+#[cfg(feature = "std")]
+impl<'a> Sum<&'a Self> for Vec3 {
+    fn sum<I>(iter: I) -> Self
+    where
+        I: Iterator<Item = &'a Self>,
+    {
+        iter.fold(ZERO, |a, &b| Self::add(a, b))
+    }
+}
+
+#[cfg(feature = "std")]
+impl<'a> Product<&'a Self> for Vec3 {
+    fn product<I>(iter: I) -> Self
+    where
+        I: Iterator<Item = &'a Self>,
+    {
+        iter.fold(ONE, |a, &b| Self::mul(a, b))
+    }
+}
\ No newline at end of file
diff --git a/src/f32/vec3a.rs b/src/f32/vec3a.rs
index f515282..5b6ef6f 100644
--- a/src/f32/vec3a.rs
+++ b/src/f32/vec3a.rs
@@ -9,6 +9,9 @@ use core::arch::x86_64::*;
 #[cfg(vec3a_sse2)]
 use core::{cmp::Ordering, f32, mem::MaybeUninit};
 
+#[cfg(feature = "std")]
+use std::iter::{Product, Sum};
+
 #[cfg(vec3a_sse2)]
 use crate::Align16;
 
@@ -1197,6 +1200,26 @@ impl From<Vec3A> for Vec2 {
     }
 }
 
+#[cfg(feature = "std")]
+impl<'a> Sum<&'a Self> for Vec3A {
+    fn sum<I>(iter: I) -> Self
+    where
+        I: Iterator<Item = &'a Self>,
+    {
+        iter.fold(ZERO, |a, &b| Self::add(a, b))
+    }
+}
+
+#[cfg(feature = "std")]
+impl<'a> Product<&'a Self> for Vec3A {
+    fn product<I>(iter: I) -> Self
+    where
+        I: Iterator<Item = &'a Self>,
+    {
+        iter.fold(ONE, |a, &b| Self::mul(a, b))
+    }
+}
+
 #[test]
 fn test_vec3_private() {
     assert_eq!(
diff --git a/src/f32/vec4.rs b/src/f32/vec4.rs
index ef99d92..1bcb3d8 100644
--- a/src/f32/vec4.rs
+++ b/src/f32/vec4.rs
@@ -6,6 +6,9 @@ use core::arch::x86::*;
 #[cfg(all(vec4_sse2, target_arch = "x86_64"))]
 use core::arch::x86_64::*;
 
+#[cfg(feature = "std")]
+use std::iter::{Product, Sum};
+
 #[cfg(vec4_sse2)]
 use crate::Align16;
 #[cfg(vec4_sse2)]
@@ -1359,6 +1362,26 @@ impl From<Vec4> for Vec2 {
     }
 }
 
+#[cfg(feature = "std")]
+impl<'a> Sum<&'a Self> for Vec4 {
+    fn sum<I>(iter: I) -> Self
+    where
+        I: Iterator<Item = &'a Self>,
+    {
+        iter.fold(ZERO, |a, &b| Self::add(a, b))
+    }
+}
+
+#[cfg(feature = "std")]
+impl<'a> Product<&'a Self> for Vec4 {
+    fn product<I>(iter: I) -> Self
+    where
+        I: Iterator<Item = &'a Self>,
+    {
+        iter.fold(ONE, |a, &b| Self::mul(a, b))
+    }
+}
+
 #[test]
 fn test_vec4_private() {
     assert_eq!(


Test patch:
diff --git a/tests/mat2.rs b/tests/mat2.rs
index a48f873..1d8e4f0 100644
--- a/tests/mat2.rs
+++ b/tests/mat2.rs
@@ -188,3 +188,17 @@ fn test_mat2_rand() {
     let b = rng2.gen::<Mat2>();
     assert_eq!(a, b);
 }
+
+#[cfg(feature = "std")]
+#[test]
+fn test_sum() {
+    let id = Mat2::identity();
+    assert_eq!(vec![id, id].iter().sum::<Mat2>(), id + id);
+}
+
+#[cfg(feature = "std")]
+#[test]
+fn test_product() {
+    let two = Mat2::identity() + Mat2::identity();
+    assert_eq!(vec![two, two].iter().product::<Mat2>(), two * two);
+}
\ No newline at end of file
diff --git a/tests/mat3.rs b/tests/mat3.rs
index 1647e03..273a694 100644
--- a/tests/mat3.rs
+++ b/tests/mat3.rs
@@ -254,3 +254,17 @@ fn test_mat3_rand() {
     let b = rng2.gen::<Mat3>();
     assert_eq!(a, b);
 }
+
+#[cfg(feature = "std")]
+#[test]
+fn test_sum() {
+    let id = Mat3::identity();
+    assert_eq!(vec![id, id].iter().sum::<Mat3>(), id + id);
+}
+
+#[cfg(feature = "std")]
+#[test]
+fn test_product() {
+    let two = Mat3::identity() + Mat3::identity();
+    assert_eq!(vec![two, two].iter().product::<Mat3>(), two * two);
+}
\ No newline at end of file
diff --git a/tests/mat4.rs b/tests/mat4.rs
index d2c10fd..6162183 100644
--- a/tests/mat4.rs
+++ b/tests/mat4.rs
@@ -537,3 +537,17 @@ fn test_mat4_rand() {
     let b = rng2.gen::<Mat4>();
     assert_eq!(a, b);
 }
+
+#[cfg(feature = "std")]
+#[test]
+fn test_sum() {
+    let id = Mat4::identity();
+    assert_eq!(vec![id, id].iter().sum::<Mat4>(), id + id);
+}
+
+#[cfg(feature = "std")]
+#[test]
+fn test_product() {
+    let two = Mat4::identity() + Mat4::identity();
+    assert_eq!(vec![two, two].iter().product::<Mat4>(), two * two);
+}
\ No newline at end of file
diff --git a/tests/quat.rs b/tests/quat.rs
index 6a279fd..38908f9 100644
--- a/tests/quat.rs
+++ b/tests/quat.rs
@@ -388,3 +388,17 @@ fn test_quat_rand() {
     let b: Quat = rng2.gen();
     assert_eq!(a, b);
 }
+
+#[cfg(feature = "std")]
+#[test]
+fn test_sum() {
+    let two = quat(2.0, 2.0, 2.0, 2.0);
+    assert_eq!(vec![two, two].iter().sum::<Quat>(), two + two);
+}
+
+#[cfg(feature = "std")]
+#[test]
+fn test_product() {
+    let two = quat(2.0, 2.0, 2.0, 2.0);
+    assert_eq!(vec![two, two].iter().product::<Quat>(), two * two);
+}
\ No newline at end of file
diff --git a/tests/vec2.rs b/tests/vec2.rs
index 344fd39..9530d96 100644
--- a/tests/vec2.rs
+++ b/tests/vec2.rs
@@ -496,3 +496,17 @@ fn test_vec2_rand() {
     let b: Vec2 = rng2.gen();
     assert_eq!(a, b.into());
 }
+
+#[cfg(feature = "std")]
+#[test]
+fn test_sum() {
+    let one = Vec2::one();
+    assert_eq!(vec![one, one].iter().sum::<Vec2>(), one + one);
+}
+
+#[cfg(feature = "std")]
+#[test]
+fn test_product() {
+    let two = Vec2::new(2.0, 2.0);
+    assert_eq!(vec![two, two].iter().product::<Vec2>(), two * two);
+}
diff --git a/tests/vec3.rs b/tests/vec3.rs
index 129cfa5..30e056d 100644
--- a/tests/vec3.rs
+++ b/tests/vec3.rs
@@ -561,3 +561,18 @@ fn test_vec3_rand() {
     let b: Vec3 = rng2.gen();
     assert_eq!(a, b.into());
 }
+
+#[cfg(feature = "std")]
+#[test]
+fn test_sum() {
+    let one = Vec3::one();
+    assert_eq!(vec![one, one].iter().sum::<Vec3>(), one + one);
+}
+
+#[cfg(feature = "std")]
+#[test]
+fn test_product() {
+    let two = Vec3::new(2.0, 2.0, 2.0);
+    assert_eq!(vec![two, two].iter().product::<Vec3>(), two * two);
+}
+
diff --git a/tests/vec3a.rs b/tests/vec3a.rs
index bc7b732..d278dce 100644
--- a/tests/vec3a.rs
+++ b/tests/vec3a.rs
@@ -599,3 +599,17 @@ fn test_vec3a_rand() {
     let b: Vec3A = rng2.gen();
     assert_eq!(a, b.into());
 }
+
+#[cfg(feature = "std")]
+#[test]
+fn test_sum() {
+    let one = Vec3A::one();
+    assert_eq!(vec![one, one].iter().sum::<Vec3A>(), one + one);
+}
+
+#[cfg(feature = "std")]
+#[test]
+fn test_product() {
+    let two = Vec3A::new(2.0, 2.0, 2.0);
+    assert_eq!(vec![two, two].iter().product::<Vec3A>(), two * two);
+}
diff --git a/tests/vec4.rs b/tests/vec4.rs
index 8fe858a..fdb63e2 100644
--- a/tests/vec4.rs
+++ b/tests/vec4.rs
@@ -635,3 +635,17 @@ fn test_vec4_rand() {
     let b: Vec4 = rng2.gen();
     assert_eq!(a, b.into());
 }
+
+#[cfg(feature = "std")]
+#[test]
+fn test_sum() {
+    let one = Vec4::one();
+    assert_eq!(vec![one, one].iter().sum::<Vec4>(), one + one);
+}
+
+#[cfg(feature = "std")]
+#[test]
+fn test_product() {
+    let two = Vec4::new(2.0, 2.0, 2.0, 2.0);
+    assert_eq!(vec![two, two].iter().product::<Vec4>(), two * two);
+}