Support for scalar on the lhs of arithmetic operators

This commit is contained in:
Cameron Hart 2016-01-01 18:05:32 +11:00
parent 6cf7831275
commit 7426d8d807
3 changed files with 81 additions and 0 deletions

View file

@ -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 {

View file

@ -244,6 +244,7 @@ macro_rules! impl_vector {
impl_operator!(<S: BaseNum> Mul<$VectorN<S> > for $VectorN<S> {
fn mul(lhs, rhs) -> $VectorN<S> { $VectorN::new($(lhs.$field * rhs.$field),+) }
});
impl_assignment_operator!(<S: BaseNum> MulAssign<S> for $VectorN<S> {
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<S> { x, y }, 2, vec2);
impl_vector!(Vector3<S> { x, y, z }, 3, vec3);
impl_vector!(Vector4<S> { 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<S> { x: 0, y: 1 }, 2);
impl_fixed_array_conversions!(Vector3<S> { x: 0, y: 1, z: 2 }, 3);
impl_fixed_array_conversions!(Vector4<S> { x: 0, y: 1, z: 2, w: 3 }, 4);

View file

@ -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);