From 7426d8d807ebfd19833aefa13be4236cedf4a062 Mon Sep 17 00:00:00 2001 From: Cameron Hart Date: Fri, 1 Jan 2016 18:05:32 +1100 Subject: [PATCH] Support for scalar on the lhs of arithmetic operators --- src/macros.rs | 32 ++++++++++++++++++++++++++++++++ src/vector.rs | 11 +++++++++++ tests/vector.rs | 38 ++++++++++++++++++++++++++++++++++++++ 3 files changed, 81 insertions(+) diff --git a/src/macros.rs b/src/macros.rs index ed2223a..fc5d43f 100644 --- a/src/macros.rs +++ b/src/macros.rs @@ -95,6 +95,38 @@ macro_rules! impl_operator { } } }; + // When the left operand is a scalar + ($Op:ident<$Rhs:ident<$S:ident>> for $Lhs:ty { + fn $op:ident($lhs:ident, $rhs:ident) -> $Output:ty { $body:expr } + }) => { + impl $Op<$Rhs<$S>> for $Lhs { + type Output = $Output; + #[inline] + fn $op(self, other: $Rhs<$S>) -> $Output { + let ($lhs, $rhs) = (self, other); $body + } + } + }; +} + +macro_rules! impl_scalar_ops { + ($VectorN:ident<$S:ident> { $($field:ident),+ }) => { + impl_operator!(Add<$VectorN<$S>> for $S { + fn add(scalar, vector) -> $VectorN<$S> { $VectorN::new($(scalar + vector.$field),+) } + }); + impl_operator!(Sub<$VectorN<$S>> for $S { + fn sub(scalar, vector) -> $VectorN<$S> { $VectorN::new($(scalar - vector.$field),+) } + }); + impl_operator!(Mul<$VectorN<$S>> for $S { + fn mul(scalar, vector) -> $VectorN<$S> { $VectorN::new($(scalar * vector.$field),+) } + }); + impl_operator!(Div<$VectorN<$S>> for $S { + fn div(scalar, vector) -> $VectorN<$S> { $VectorN::new($(scalar / vector.$field),+) } + }); + impl_operator!(Rem<$VectorN<$S>> for $S { + fn rem(scalar, vector) -> $VectorN<$S> { $VectorN::new($(scalar % vector.$field),+) } + }); + }; } macro_rules! impl_assignment_operator { diff --git a/src/vector.rs b/src/vector.rs index 91abfcb..0d47c75 100644 --- a/src/vector.rs +++ b/src/vector.rs @@ -244,6 +244,7 @@ macro_rules! impl_vector { impl_operator!( Mul<$VectorN > for $VectorN { fn mul(lhs, rhs) -> $VectorN { $VectorN::new($(lhs.$field * rhs.$field),+) } }); + impl_assignment_operator!( MulAssign for $VectorN { fn mul_assign(&mut self, scalar) { $(self.$field *= scalar);+ } }); @@ -285,10 +286,20 @@ macro_rules! impl_vector { } } +macro_rules! impl_vector_scalar_ops { + ($($S:ident)*) => ($( + impl_scalar_ops!(Vector2<$S> { x, y }); + impl_scalar_ops!(Vector3<$S> { x, y, z }); + impl_scalar_ops!(Vector4<$S> { x, y, z, w }); + )*) +} + impl_vector!(Vector2 { x, y }, 2, vec2); impl_vector!(Vector3 { x, y, z }, 3, vec3); impl_vector!(Vector4 { x, y, z, w }, 4, vec4); +impl_vector_scalar_ops!(usize u8 u16 u32 u64 isize i8 i16 i32 i64 f32 f64); + impl_fixed_array_conversions!(Vector2 { x: 0, y: 1 }, 2); impl_fixed_array_conversions!(Vector3 { x: 0, y: 1, z: 2 }, 3); impl_fixed_array_conversions!(Vector4 { x: 0, y: 1, z: 2, w: 3 }, 4); diff --git a/tests/vector.rs b/tests/vector.rs index cd76a1b..4950021 100644 --- a/tests/vector.rs +++ b/tests/vector.rs @@ -33,6 +33,44 @@ fn test_from_value() { assert_eq!(Vector4::from_value(76.5f64), Vector4::new(76.5f64, 76.5f64, 76.5f64, 76.5f64)); } +macro_rules! test_ops { + ($VectorN:ident { $($field:ident),+ }, $s:expr, $v:expr) => ( + // add + assert_eq!($v + $s, $VectorN::new($($v.$field + $s),+)); + assert_eq!($s + $v, $VectorN::new($($s + $v.$field),+)); + assert_eq!($v + $s, $s + $v); + // sub + assert_eq!($v - $s, $VectorN::new($($v.$field - $s),+)); + assert_eq!($s - $v, $VectorN::new($($s - $v.$field),+)); + assert_eq!($v - $s, -($s - $v)); + // mul + assert_eq!($v * $s, $VectorN::new($($v.$field * $s),+)); + assert_eq!($s * $v, $VectorN::new($($s * $v.$field),+)); + assert_eq!($v * $s, $s * $v); + // div + assert_eq!($v / $s, $VectorN::new($($v.$field / $s),+)); + assert_eq!($s / $v, $VectorN::new($($s / $v.$field),+)); + // rem + assert_eq!($v % $s, $VectorN::new($($v.$field % $s),+)); + assert_eq!($s % $v, $VectorN::new($($s % $v.$field),+)); + ) +} + +#[test] +fn test_ops() { + let a = [3.0f32, 4.0f32, 5.0f32, 6.0f32]; + let s = 2.0f32; + + let v4 = Vector4::from(a); + test_ops!(Vector4 { x, y, z, w }, s, v4); + + let v3 = v4.truncate(); + test_ops!(Vector3 { x, y, z }, s, v3); + + let v2 = v3.truncate(); + test_ops!(Vector2 { x, y }, s, v2); +} + #[test] fn test_dot() { assert_eq!(Vector2::new(1isize, 2isize).dot(Vector2::new(3isize, 4isize)), 11isize);