From 7426d8d807ebfd19833aefa13be4236cedf4a062 Mon Sep 17 00:00:00 2001 From: Cameron Hart Date: Fri, 1 Jan 2016 18:05:32 +1100 Subject: [PATCH 1/7] 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); From 338c4947359915ddcc4a83bfab7ca977178785f7 Mon Sep 17 00:00:00 2001 From: Cameron Hart Date: Sat, 2 Jan 2016 00:09:11 +1100 Subject: [PATCH 2/7] Make macro usage more like existing style --- src/macros.rs | 26 +++++++------------------- src/vector.rs | 39 +++++++++++++++++++++++++++++++-------- 2 files changed, 38 insertions(+), 27 deletions(-) diff --git a/src/macros.rs b/src/macros.rs index fc5d43f..c4d60a2 100644 --- a/src/macros.rs +++ b/src/macros.rs @@ -106,26 +106,14 @@ macro_rules! impl_operator { 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),+) } - }); + impl<'a> $Op<&'a $Rhs<$S>> for $Lhs { + type Output = $Output; + #[inline] + fn $op(self, other: &'a $Rhs<$S>) -> $Output { + let ($lhs, $rhs) = (self, other); $body + } + } }; } diff --git a/src/vector.rs b/src/vector.rs index 0d47c75..75e4e1e 100644 --- a/src/vector.rs +++ b/src/vector.rs @@ -278,6 +278,19 @@ macro_rules! impl_vector { fn rem_assign(&mut self, other) { $(self.$field %= other.$field);+ } }); + impl_scalar_ops!($VectorN { $($field),+ }); + impl_scalar_ops!($VectorN { $($field),+ }); + impl_scalar_ops!($VectorN { $($field),+ }); + impl_scalar_ops!($VectorN { $($field),+ }); + impl_scalar_ops!($VectorN { $($field),+ }); + impl_scalar_ops!($VectorN { $($field),+ }); + impl_scalar_ops!($VectorN { $($field),+ }); + impl_scalar_ops!($VectorN { $($field),+ }); + impl_scalar_ops!($VectorN { $($field),+ }); + impl_scalar_ops!($VectorN { $($field),+ }); + impl_scalar_ops!($VectorN { $($field),+ }); + impl_scalar_ops!($VectorN { $($field),+ }); + impl_index_operators!($VectorN, $n, S, usize); impl_index_operators!($VectorN, $n, [S], Range); impl_index_operators!($VectorN, $n, [S], RangeTo); @@ -286,20 +299,30 @@ 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 }); - )*) +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),+) } + }); + }; } 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); From 043a63c45a6318829c36d35b836635173594311e Mon Sep 17 00:00:00 2001 From: Cameron Hart Date: Sat, 2 Jan 2016 00:18:48 +1100 Subject: [PATCH 3/7] Expand vector aritmetic operator tests Add test for vector on vector operators and different permutations of vector references. --- tests/vector.rs | 77 +++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 71 insertions(+), 6 deletions(-) diff --git a/tests/vector.rs b/tests/vector.rs index 4950021..520a4e8 100644 --- a/tests/vector.rs +++ b/tests/vector.rs @@ -33,26 +33,91 @@ 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 { +macro_rules! test_op_add { ($VectorN:ident { $($field:ident),+ }, $s:expr, $v:expr) => ( - // add + // vector + vector ops + assert_eq!($v + $v, $VectorN::new($($v.$field + $v.$field),+)); + assert_eq!(&$v + &$v, $VectorN::new($($v.$field + $v.$field),+)); + assert_eq!(&$v + $v, $VectorN::new($($v.$field + $v.$field),+)); + assert_eq!($v + &$v, $VectorN::new($($v.$field + $v.$field),+)); + // vector + scalar ops assert_eq!($v + $s, $VectorN::new($($v.$field + $s),+)); assert_eq!($s + $v, $VectorN::new($($s + $v.$field),+)); + 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 + ) +} + +macro_rules! test_op_sub { + ($VectorN:ident { $($field:ident),+ }, $s:expr, $v:expr) => ( + // vector - vector ops + assert_eq!($v - $v, $VectorN::new($($v.$field - $v.$field),+)); + assert_eq!(&$v - &$v, $VectorN::new($($v.$field - $v.$field),+)); + assert_eq!(&$v - $v, $VectorN::new($($v.$field - $v.$field),+)); + assert_eq!($v - &$v, $VectorN::new($($v.$field - $v.$field),+)); + // vector - scalar ops assert_eq!($v - $s, $VectorN::new($($v.$field - $s),+)); assert_eq!($s - $v, $VectorN::new($($s - $v.$field),+)); + 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 + ) +} + +macro_rules! test_op_mul { + ($VectorN:ident { $($field:ident),+ }, $s:expr, $v:expr) => ( + // vector * vector ops + assert_eq!($v * $v, $VectorN::new($($v.$field * $v.$field),+)); + assert_eq!(&$v * &$v, $VectorN::new($($v.$field * $v.$field),+)); + assert_eq!(&$v * $v, $VectorN::new($($v.$field * $v.$field),+)); + assert_eq!($v * &$v, $VectorN::new($($v.$field * $v.$field),+)); + // vector * scalar ops assert_eq!($v * $s, $VectorN::new($($v.$field * $s),+)); assert_eq!($s * $v, $VectorN::new($($s * $v.$field),+)); + 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 + ) +} + +macro_rules! test_op_div { + ($VectorN:ident { $($field:ident),+ }, $s:expr, $v:expr) => ( + // vector / vector ops + assert_eq!($v / $v, $VectorN::new($($v.$field / $v.$field),+)); + assert_eq!(&$v / &$v, $VectorN::new($($v.$field / $v.$field),+)); + assert_eq!(&$v / $v, $VectorN::new($($v.$field / $v.$field),+)); + assert_eq!($v / &$v, $VectorN::new($($v.$field / $v.$field),+)); + // vector / scalar ops 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),+)); + ) +} + +macro_rules! test_op_rem { + ($VectorN:ident { $($field:ident),+ }, $s:expr, $v:expr) => ( + // vector % vector ops + assert_eq!($v % $v, $VectorN::new($($v.$field % $v.$field),+)); + assert_eq!(&$v % &$v, $VectorN::new($($v.$field % $v.$field),+)); + assert_eq!(&$v % $v, $VectorN::new($($v.$field % $v.$field),+)); + assert_eq!($v % &$v, $VectorN::new($($v.$field % $v.$field),+)); + // vector % scalar ops assert_eq!($v % $s, $VectorN::new($($v.$field % $s),+)); assert_eq!($s % $v, $VectorN::new($($s % $v.$field),+)); + assert_eq!(&$v % $s, $VectorN::new($($v.$field % $s),+)); + assert_eq!($s % &$v, $VectorN::new($($s % $v.$field),+)); + ) +} + +macro_rules! test_ops { + ($VectorN:ident { $($field:ident),+ }, $s:expr, $v:expr) => ( + test_op_add!($VectorN { $($field),+ }, $s, $v); + test_op_sub!($VectorN { $($field),+ }, $s, $v); + test_op_mul!($VectorN { $($field),+ }, $s, $v); + test_op_div!($VectorN { $($field),+ }, $s, $v); + test_op_rem!($VectorN { $($field),+ }, $s, $v); ) } From 62b6c961a42399b65b0ae54dc1b124ee274b65bc Mon Sep 17 00:00:00 2001 From: Cameron Hart Date: Sat, 2 Jan 2016 08:57:16 +1100 Subject: [PATCH 4/7] Test by-ref arithmetic operators against by-val results --- tests/vector.rs | 53 ++++++++++++++++++++++++++----------------------- 1 file changed, 28 insertions(+), 25 deletions(-) diff --git a/tests/vector.rs b/tests/vector.rs index 520a4e8..cd82bee 100644 --- a/tests/vector.rs +++ b/tests/vector.rs @@ -37,14 +37,15 @@ macro_rules! test_op_add { ($VectorN:ident { $($field:ident),+ }, $s:expr, $v:expr) => ( // vector + vector ops assert_eq!($v + $v, $VectorN::new($($v.$field + $v.$field),+)); - assert_eq!(&$v + &$v, $VectorN::new($($v.$field + $v.$field),+)); - assert_eq!(&$v + $v, $VectorN::new($($v.$field + $v.$field),+)); - assert_eq!($v + &$v, $VectorN::new($($v.$field + $v.$field),+)); + assert_eq!(&$v + &$v, $v + $v); + assert_eq!(&$v + $v, $v + $v); + assert_eq!($v + &$v, $v + $v); // vector + scalar ops assert_eq!($v + $s, $VectorN::new($($v.$field + $s),+)); assert_eq!($s + $v, $VectorN::new($($s + $v.$field),+)); - assert_eq!(&$v + $s, $VectorN::new($($v.$field + $s),+)); - assert_eq!($s + &$v, $VectorN::new($($s + $v.$field),+)); + assert_eq!(&$v + $s, $v + $s); + assert_eq!($s + &$v, $s + $v); + // commutativity assert_eq!($v + $s, $s + $v); ) } @@ -53,14 +54,15 @@ macro_rules! test_op_sub { ($VectorN:ident { $($field:ident),+ }, $s:expr, $v:expr) => ( // vector - vector ops assert_eq!($v - $v, $VectorN::new($($v.$field - $v.$field),+)); - assert_eq!(&$v - &$v, $VectorN::new($($v.$field - $v.$field),+)); - assert_eq!(&$v - $v, $VectorN::new($($v.$field - $v.$field),+)); - assert_eq!($v - &$v, $VectorN::new($($v.$field - $v.$field),+)); + assert_eq!(&$v - &$v, $v - $v); + assert_eq!(&$v - $v, $v - $v); + assert_eq!($v - &$v, $v - $v); // vector - scalar ops assert_eq!($v - $s, $VectorN::new($($v.$field - $s),+)); assert_eq!($s - $v, $VectorN::new($($s - $v.$field),+)); - assert_eq!(&$v - $s, $VectorN::new($($v.$field - $s),+)); - assert_eq!($s - &$v, $VectorN::new($($s - $v.$field),+)); + assert_eq!(&$v - $s, $v - $s); + assert_eq!($s - &$v, $s - $v); + // commutativity assert_eq!($v - $s, -($s - $v)); ) } @@ -69,14 +71,15 @@ macro_rules! test_op_mul { ($VectorN:ident { $($field:ident),+ }, $s:expr, $v:expr) => ( // vector * vector ops assert_eq!($v * $v, $VectorN::new($($v.$field * $v.$field),+)); - assert_eq!(&$v * &$v, $VectorN::new($($v.$field * $v.$field),+)); - assert_eq!(&$v * $v, $VectorN::new($($v.$field * $v.$field),+)); - assert_eq!($v * &$v, $VectorN::new($($v.$field * $v.$field),+)); + assert_eq!(&$v * &$v, $v * $v); + assert_eq!(&$v * $v, $v * $v); + assert_eq!($v * &$v, $v * $v); // vector * scalar ops assert_eq!($v * $s, $VectorN::new($($v.$field * $s),+)); assert_eq!($s * $v, $VectorN::new($($s * $v.$field),+)); - assert_eq!(&$v * $s, $VectorN::new($($v.$field * $s),+)); - assert_eq!($s * &$v, $VectorN::new($($s * $v.$field),+)); + assert_eq!(&$v * $s, $v * $s); + assert_eq!($s * &$v, $s * $v); + // commutativity assert_eq!($v * $s, $s * $v); ) } @@ -85,14 +88,14 @@ macro_rules! test_op_div { ($VectorN:ident { $($field:ident),+ }, $s:expr, $v:expr) => ( // vector / vector ops assert_eq!($v / $v, $VectorN::new($($v.$field / $v.$field),+)); - assert_eq!(&$v / &$v, $VectorN::new($($v.$field / $v.$field),+)); - assert_eq!(&$v / $v, $VectorN::new($($v.$field / $v.$field),+)); - assert_eq!($v / &$v, $VectorN::new($($v.$field / $v.$field),+)); + assert_eq!(&$v / &$v, $v / $v); + assert_eq!(&$v / $v, $v / $v); + assert_eq!($v / &$v, $v / $v); // vector / scalar ops assert_eq!($v / $s, $VectorN::new($($v.$field / $s),+)); assert_eq!($s / $v, $VectorN::new($($s / $v.$field),+)); - assert_eq!(&$v / $s, $VectorN::new($($v.$field / $s),+)); - assert_eq!($s / &$v, $VectorN::new($($s / $v.$field),+)); + assert_eq!(&$v / $s, $v / $s); + assert_eq!($s / &$v, $s / $v); ) } @@ -100,14 +103,14 @@ macro_rules! test_op_rem { ($VectorN:ident { $($field:ident),+ }, $s:expr, $v:expr) => ( // vector % vector ops assert_eq!($v % $v, $VectorN::new($($v.$field % $v.$field),+)); - assert_eq!(&$v % &$v, $VectorN::new($($v.$field % $v.$field),+)); - assert_eq!(&$v % $v, $VectorN::new($($v.$field % $v.$field),+)); - assert_eq!($v % &$v, $VectorN::new($($v.$field % $v.$field),+)); + assert_eq!(&$v % &$v, $v % $v); + assert_eq!(&$v % $v, $v % $v); + assert_eq!($v % &$v, $v % $v); // vector % scalar ops assert_eq!($v % $s, $VectorN::new($($v.$field % $s),+)); assert_eq!($s % $v, $VectorN::new($($s % $v.$field),+)); - assert_eq!(&$v % $s, $VectorN::new($($v.$field % $s),+)); - assert_eq!($s % &$v, $VectorN::new($($s % $v.$field),+)); + assert_eq!(&$v % $s, $v % $s); + assert_eq!($s % &$v, $s % $v); ) } From 1e6f615f9ef3ea14a13726253281264b65161d06 Mon Sep 17 00:00:00 2001 From: Cameron Hart Date: Sat, 2 Jan 2016 09:12:13 +1100 Subject: [PATCH 5/7] Split arithmetic operator tests into per op tests --- tests/vector.rs | 54 +++++++++++++++++++++++++++++-------------------- 1 file changed, 32 insertions(+), 22 deletions(-) diff --git a/tests/vector.rs b/tests/vector.rs index cd82bee..b076f8b 100644 --- a/tests/vector.rs +++ b/tests/vector.rs @@ -33,7 +33,7 @@ fn test_from_value() { assert_eq!(Vector4::from_value(76.5f64), Vector4::new(76.5f64, 76.5f64, 76.5f64, 76.5f64)); } -macro_rules! test_op_add { +macro_rules! impl_test_add { ($VectorN:ident { $($field:ident),+ }, $s:expr, $v:expr) => ( // vector + vector ops assert_eq!($v + $v, $VectorN::new($($v.$field + $v.$field),+)); @@ -50,7 +50,7 @@ macro_rules! test_op_add { ) } -macro_rules! test_op_sub { +macro_rules! impl_test_sub { ($VectorN:ident { $($field:ident),+ }, $s:expr, $v:expr) => ( // vector - vector ops assert_eq!($v - $v, $VectorN::new($($v.$field - $v.$field),+)); @@ -67,7 +67,7 @@ macro_rules! test_op_sub { ) } -macro_rules! test_op_mul { +macro_rules! impl_test_mul { ($VectorN:ident { $($field:ident),+ }, $s:expr, $v:expr) => ( // vector * vector ops assert_eq!($v * $v, $VectorN::new($($v.$field * $v.$field),+)); @@ -84,7 +84,7 @@ macro_rules! test_op_mul { ) } -macro_rules! test_op_div { +macro_rules! impl_test_div { ($VectorN:ident { $($field:ident),+ }, $s:expr, $v:expr) => ( // vector / vector ops assert_eq!($v / $v, $VectorN::new($($v.$field / $v.$field),+)); @@ -99,7 +99,7 @@ macro_rules! test_op_div { ) } -macro_rules! test_op_rem { +macro_rules! impl_test_rem { ($VectorN:ident { $($field:ident),+ }, $s:expr, $v:expr) => ( // vector % vector ops assert_eq!($v % $v, $VectorN::new($($v.$field % $v.$field),+)); @@ -114,29 +114,39 @@ macro_rules! test_op_rem { ) } -macro_rules! test_ops { - ($VectorN:ident { $($field:ident),+ }, $s:expr, $v:expr) => ( - test_op_add!($VectorN { $($field),+ }, $s, $v); - test_op_sub!($VectorN { $($field),+ }, $s, $v); - test_op_mul!($VectorN { $($field),+ }, $s, $v); - test_op_div!($VectorN { $($field),+ }, $s, $v); - test_op_rem!($VectorN { $($field),+ }, $s, $v); - ) +#[test] +fn test_add() { + impl_test_add!(Vector4 { x, y, z, w }, 2.0f32, vec4(2.0f32, 4.0, 6.0, 8.0)); + impl_test_add!(Vector3 { x, y, z }, 2.0f32, vec3(2.0f32, 4.0, 6.0)); + impl_test_add!(Vector2 { x, y }, 2.0f32, vec2(2.0f32, 4.0)); } #[test] -fn test_ops() { - let a = [3.0f32, 4.0f32, 5.0f32, 6.0f32]; - let s = 2.0f32; +fn test_sub() { + impl_test_sub!(Vector4 { x, y, z, w }, 2.0f32, vec4(2.0f32, 4.0, 6.0, 8.0)); + impl_test_sub!(Vector3 { x, y, z }, 2.0f32, vec3(2.0f32, 4.0, 6.0)); + impl_test_sub!(Vector2 { x, y }, 2.0f32, vec2(2.0f32, 4.0)); +} - let v4 = Vector4::from(a); - test_ops!(Vector4 { x, y, z, w }, s, v4); +#[test] +fn test_mul() { + impl_test_mul!(Vector4 { x, y, z, w }, 2.0f32, vec4(2.0f32, 4.0, 6.0, 8.0)); + impl_test_mul!(Vector3 { x, y, z }, 2.0f32, vec3(2.0f32, 4.0, 6.0)); + impl_test_mul!(Vector2 { x, y }, 2.0f32, vec2(2.0f32, 4.0)); +} - let v3 = v4.truncate(); - test_ops!(Vector3 { x, y, z }, s, v3); +#[test] +fn test_div() { + impl_test_div!(Vector4 { x, y, z, w }, 2.0f32, vec4(2.0f32, 4.0, 6.0, 8.0)); + impl_test_div!(Vector3 { x, y, z }, 2.0f32, vec3(2.0f32, 4.0, 6.0)); + impl_test_div!(Vector2 { x, y }, 2.0f32, vec2(2.0f32, 4.0)); +} - let v2 = v3.truncate(); - test_ops!(Vector2 { x, y }, s, v2); +#[test] +fn test_rem() { + impl_test_rem!(Vector4 { x, y, z, w }, 2.0f32, vec4(2.0f32, 4.0, 6.0, 8.0)); + impl_test_rem!(Vector3 { x, y, z }, 2.0f32, vec3(2.0f32, 4.0, 6.0)); + impl_test_rem!(Vector2 { x, y }, 2.0f32, vec2(2.0f32, 4.0)); } #[test] From 3febc46d5a3426d28d82b768d6d264c1f3492c5b Mon Sep 17 00:00:00 2001 From: Cameron Hart Date: Sat, 2 Jan 2016 10:14:47 +1100 Subject: [PATCH 6/7] Added scalar arithmetic operators for Point types --- src/point.rs | 27 +++++++++++++++++++++++++ tests/point.rs | 53 +++++++++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 79 insertions(+), 1 deletion(-) diff --git a/src/point.rs b/src/point.rs index 362f1b8..33dfc14 100644 --- a/src/point.rs +++ b/src/point.rs @@ -172,6 +172,19 @@ macro_rules! impl_point { fn rem_assign(&mut self, scalar) { $(self.$field %= scalar);+ } }); + impl_scalar_ops!($PointN { $($field),+ }); + impl_scalar_ops!($PointN { $($field),+ }); + impl_scalar_ops!($PointN { $($field),+ }); + impl_scalar_ops!($PointN { $($field),+ }); + impl_scalar_ops!($PointN { $($field),+ }); + impl_scalar_ops!($PointN { $($field),+ }); + impl_scalar_ops!($PointN { $($field),+ }); + impl_scalar_ops!($PointN { $($field),+ }); + impl_scalar_ops!($PointN { $($field),+ }); + impl_scalar_ops!($PointN { $($field),+ }); + impl_scalar_ops!($PointN { $($field),+ }); + impl_scalar_ops!($PointN { $($field),+ }); + impl_index_operators!($PointN, $n, S, usize); impl_index_operators!($PointN, $n, [S], Range); impl_index_operators!($PointN, $n, [S], RangeTo); @@ -180,6 +193,20 @@ macro_rules! impl_point { } } +macro_rules! impl_scalar_ops { + ($PointN:ident<$S:ident> { $($field:ident),+ }) => { + impl_operator!(Mul<$PointN<$S>> for $S { + fn mul(scalar, vector) -> $PointN<$S> { $PointN::new($(scalar * vector.$field),+) } + }); + impl_operator!(Div<$PointN<$S>> for $S { + fn div(scalar, vector) -> $PointN<$S> { $PointN::new($(scalar / vector.$field),+) } + }); + impl_operator!(Rem<$PointN<$S>> for $S { + fn rem(scalar, vector) -> $PointN<$S> { $PointN::new($(scalar % vector.$field),+) } + }); + }; +} + impl_point!(Point2 { x, y }, Vector2, 2); impl_point!(Point3 { x, y, z }, Vector3, 3); diff --git a/tests/point.rs b/tests/point.rs index 3dbfef6..fcd2714 100644 --- a/tests/point.rs +++ b/tests/point.rs @@ -16,11 +16,62 @@ extern crate cgmath; -use cgmath::Point3; +use cgmath::{Point2, Point3}; use cgmath::ApproxEq; +macro_rules! impl_test_mul { + ($PointN:ident { $($field:ident),+ }, $s:expr, $v:expr) => ( + // point * scalar ops + assert_eq!($v * $s, $PointN::new($($v.$field * $s),+)); + assert_eq!($s * $v, $PointN::new($($s * $v.$field),+)); + assert_eq!(&$v * $s, $v * $s); + assert_eq!($s * &$v, $s * $v); + // commutativity + assert_eq!($v * $s, $s * $v); + ) +} + +macro_rules! impl_test_div { + ($PointN:ident { $($field:ident),+ }, $s:expr, $v:expr) => ( + // point / scalar ops + assert_eq!($v / $s, $PointN::new($($v.$field / $s),+)); + assert_eq!($s / $v, $PointN::new($($s / $v.$field),+)); + assert_eq!(&$v / $s, $v / $s); + assert_eq!($s / &$v, $s / $v); + ) +} + +macro_rules! impl_test_rem { + ($PointN:ident { $($field:ident),+ }, $s:expr, $v:expr) => ( + // point % scalar ops + assert_eq!($v % $s, $PointN::new($($v.$field % $s),+)); + assert_eq!($s % $v, $PointN::new($($s % $v.$field),+)); + assert_eq!(&$v % $s, $v % $s); + assert_eq!($s % &$v, $s % $v); + ) +} + #[test] fn test_homogeneous() { let p = Point3::new(1.0f64, 2.0f64, 3.0f64); assert!(p.approx_eq(&Point3::from_homogeneous(p.to_homogeneous()))); } + +#[test] +fn test_mul() { + impl_test_mul!(Point3 { x, y, z }, 2.0f32, Point3::new(2.0f32, 4.0, 6.0)); + impl_test_mul!(Point2 { x, y }, 2.0f32, Point2::new(2.0f32, 4.0)); +} + +#[test] +fn test_div() { + impl_test_div!(Point3 { x, y, z }, 2.0f32, Point3::new(2.0f32, 4.0, 6.0)); + impl_test_div!(Point2 { x, y }, 2.0f32, Point2::new(2.0f32, 4.0)); +} + +#[test] +fn test_rem() { + impl_test_rem!(Point3 { x, y, z }, 2.0f32, Point3::new(2.0f32, 4.0, 6.0)); + impl_test_rem!(Point2 { x, y }, 2.0f32, Point2::new(2.0f32, 4.0)); +} + From 9096e409d1999fa7d4de9abe5cf3740cd01646a1 Mon Sep 17 00:00:00 2001 From: Cameron Hart Date: Sat, 2 Jan 2016 11:13:27 +1100 Subject: [PATCH 7/7] Added scalar arithmetic operators for Quaternions --- src/quaternion.rs | 25 +++++++++++++++++++++++++ tests/quaternion.rs | 36 ++++++++++++++++++++++++++++++++++++ 2 files changed, 61 insertions(+) diff --git a/src/quaternion.rs b/src/quaternion.rs index a20690d..b249960 100644 --- a/src/quaternion.rs +++ b/src/quaternion.rs @@ -167,6 +167,31 @@ impl_operator!( Mul > for Quaternion { } }); +macro_rules! impl_scalar_mul { + ($S:ident) => { + impl_operator!(Mul> for $S { + fn mul(scalar, quat) -> Quaternion<$S> { + Quaternion::from_sv(scalar * quat.s, scalar * quat.v) + } + }); + }; +} + +macro_rules! impl_scalar_div { + ($S:ident) => { + impl_operator!(Div> for $S { + fn div(scalar, quat) -> Quaternion<$S> { + Quaternion::from_sv(scalar / quat.s, scalar / quat.v) + } + }); + }; +} + +impl_scalar_mul!(f32); +impl_scalar_mul!(f64); +impl_scalar_div!(f32); +impl_scalar_div!(f64); + impl ApproxEq for Quaternion { type Epsilon = S; diff --git a/tests/quaternion.rs b/tests/quaternion.rs index e97abab..effa31e 100644 --- a/tests/quaternion.rs +++ b/tests/quaternion.rs @@ -16,6 +16,42 @@ #[macro_use] extern crate cgmath; +macro_rules! impl_test_mul { + ($s:expr, $v:expr) => ( + // point * scalar ops + assert_eq!($v * $s, Quaternion::from_sv($v.s * $s, $v.v * $s)); + assert_eq!($s * $v, Quaternion::from_sv($s * $v.s, $s * $v.v)); + assert_eq!(&$v * $s, $v * $s); + assert_eq!($s * &$v, $s * $v); + // commutativity + assert_eq!($v * $s, $s * $v); + ) +} + +macro_rules! impl_test_div { + ($s:expr, $v:expr) => ( + // point / scalar ops + assert_eq!($v / $s, Quaternion::from_sv($v.s / $s, $v.v / $s)); + assert_eq!($s / $v, Quaternion::from_sv($s / $v.s, $s / $v.v)); + assert_eq!(&$v / $s, $v / $s); + assert_eq!($s / &$v, $s / $v); + ) +} + +mod operators { + use cgmath::*; + + #[test] + fn test_mul() { + impl_test_mul!(2.0f32, Quaternion::from_euler(rad(1f32), rad(1f32), rad(1f32))); + } + + #[test] + fn test_div() { + impl_test_div!(2.0f32, Quaternion::from_euler(rad(1f32), rad(1f32), rad(1f32))); + } +} + mod to_from_euler { use std::f32;