diff --git a/godot-core/src/builtin/vectors/vector3.rs b/godot-core/src/builtin/vectors/vector3.rs index b51be691a..fd5a8ad4e 100644 --- a/godot-core/src/builtin/vectors/vector3.rs +++ b/godot-core/src/builtin/vectors/vector3.rs @@ -414,6 +414,21 @@ mod test { assert_eq_approx!(vector1.slerp(vector2, 0.5).length(), real!(6.258_311)); } + #[test] + fn iter_sum() { + let vecs = vec![ + Vector3::new(1.0, 2.0, 3.0), + Vector3::new(4.0, 5.0, 6.0), + Vector3::new(7.0, 8.0, 9.0), + ]; + + let sum_refs = vecs.iter().sum(); + let sum = vecs.into_iter().sum(); + + assert_eq_approx!(sum, Vector3::new(12.0, 15.0, 18.0)); + assert_eq_approx!(sum_refs, Vector3::new(12.0, 15.0, 18.0)); + } + #[cfg(feature = "serde")] #[test] fn serde_roundtrip() { diff --git a/godot-core/src/builtin/vectors/vector4i.rs b/godot-core/src/builtin/vectors/vector4i.rs index 631f99ed9..7db1391af 100644 --- a/godot-core/src/builtin/vectors/vector4i.rs +++ b/godot-core/src/builtin/vectors/vector4i.rs @@ -223,4 +223,15 @@ mod test { Some(Vector4Axis::W), ); } + + #[test] + fn test_iter_elementwise_prod() { + let vecs = vec![Vector4i::new(1, 2, 3, 4), Vector4i::new(5, 6, 7, 8)]; + let expected = Vector4i::new(5, 12, 21, 32); + let prod_refs: Vector4i = vecs.iter().product(); + let prod: Vector4i = vecs.into_iter().product(); + + assert_eq!(prod_refs, expected); + assert_eq!(prod, expected); + } } diff --git a/godot-core/src/builtin/vectors/vector_macros.rs b/godot-core/src/builtin/vectors/vector_macros.rs index f626f17f6..a3a6be307 100644 --- a/godot-core/src/builtin/vectors/vector_macros.rs +++ b/godot-core/src/builtin/vectors/vector_macros.rs @@ -12,8 +12,6 @@ macro_rules! impl_vector_unary_operator { ( // Name of the vector type. $Vector:ty, - // Type of each individual component, for example `i32`. - $Scalar:ty, // Names of the components, with parentheses, for example `(x, y)`. ($($components:ident),*), // Name of the operator trait, for example `Neg`. @@ -38,8 +36,6 @@ macro_rules! impl_vector_vector_binary_operator { ( // Name of the vector type. $Vector:ty, - // Type of each individual component, for example `i32`. - $Scalar:ty, // Names of the components, with parentheses, for example `(x, y)`. ($($components:ident),*), // Name of the operator trait, for example `Add`. @@ -119,8 +115,6 @@ macro_rules! impl_vector_vector_assign_operator { ( // Name of the vector type. $Vector:ty, - // Type of each individual component, for example `i32`. - $Scalar:ty, // Names of the components, with parentheses, for example `(x, y)`. ($($components:ident),*), // Name of the operator trait, for example `AddAssign`. @@ -163,6 +157,38 @@ macro_rules! impl_vector_scalar_assign_operator { } } +/// Implements a reduction (sum or product) over an iterator of vectors. +macro_rules! impl_iter_vector_reduction { + ( + // Name of the vector type. + $Vector:ty, + // Name of the reduction trait: `Sum` or `Product`. + $Operator:ident, + // Name of the function on the operator trait, for example `add`. + $func:ident + ) => { + impl std::iter::$Operator for $Vector { + #[doc = concat!("Element-wise ", stringify!($func), " of all vectors in the iterator.")] + fn $func(iter: I) -> Self + where + I: Iterator, + { + Self::from_glam(iter.map(Self::to_glam).$func()) + } + } + + impl<'a> std::iter::$Operator<&'a Self> for $Vector { + #[doc = concat!("Element-wise ", stringify!($func), " of all vectors in the iterator.")] + fn $func(iter: I) -> Self + where + I: Iterator, + { + Self::from_glam(iter.map(|x| Self::to_glam(*x)).$func()) + } + } + }; +} + /// Implements all common arithmetic operators on a built-in vector type. macro_rules! impl_vector_operators { ( @@ -173,19 +199,21 @@ macro_rules! impl_vector_operators { // Names of the components, with parentheses, for example `(x, y)`. ($($components:ident),*) ) => { - impl_vector_unary_operator!($Vector, $Scalar, ($($components),*), Neg, neg); - impl_vector_vector_binary_operator!($Vector, $Scalar, ($($components),*), Add, add); - impl_vector_vector_binary_operator!($Vector, $Scalar, ($($components),*), Sub, sub); - impl_vector_vector_binary_operator!($Vector, $Scalar, ($($components),*), Mul, mul); + impl_vector_unary_operator!($Vector, ($($components),*), Neg, neg); + impl_vector_vector_binary_operator!($Vector, ($($components),*), Add, add); + impl_vector_vector_binary_operator!($Vector, ($($components),*), Sub, sub); + impl_vector_vector_binary_operator!($Vector, ($($components),*), Mul, mul); impl_vector_scalar_binary_operator!($Vector, $Scalar, ($($components),*), Mul, mul); impl_scalar_vector_binary_operator!($Vector, $Scalar, ($($components),*), Mul, mul); - impl_vector_vector_binary_operator!($Vector, $Scalar, ($($components),*), Div, div); + impl_vector_vector_binary_operator!($Vector, ($($components),*), Div, div); impl_vector_scalar_binary_operator!($Vector, $Scalar, ($($components),*), Div, div); - impl_vector_vector_assign_operator!($Vector, $Scalar, ($($components),*), AddAssign, add_assign); - impl_vector_vector_assign_operator!($Vector, $Scalar, ($($components),*), SubAssign, sub_assign); - impl_vector_vector_assign_operator!($Vector, $Scalar, ($($components),*), MulAssign, mul_assign); + impl_iter_vector_reduction!($Vector, Sum, sum); + impl_iter_vector_reduction!($Vector, Product, product); + impl_vector_vector_assign_operator!($Vector, ($($components),*), AddAssign, add_assign); + impl_vector_vector_assign_operator!($Vector, ($($components),*), SubAssign, sub_assign); + impl_vector_vector_assign_operator!($Vector, ($($components),*), MulAssign, mul_assign); impl_vector_scalar_assign_operator!($Vector, $Scalar, ($($components),*), MulAssign, mul_assign); - impl_vector_vector_assign_operator!($Vector, $Scalar, ($($components),*), DivAssign, div_assign); + impl_vector_vector_assign_operator!($Vector, ($($components),*), DivAssign, div_assign); impl_vector_scalar_assign_operator!($Vector, $Scalar, ($($components),*), DivAssign, div_assign); } }