From cbff39b710beb40e6b0e83cf83f44110d357a5c7 Mon Sep 17 00:00:00 2001 From: harrison Date: Tue, 1 Aug 2017 00:50:03 -0400 Subject: [PATCH] condensed duplicate code for trait default specialization using macros --- src/macros.rs | 261 +++++++++++++++------------------------- src/num.rs | 10 +- src/quaternion.rs | 90 +------------- src/vector.rs | 295 +++++----------------------------------------- 4 files changed, 134 insertions(+), 522 deletions(-) diff --git a/src/macros.rs b/src/macros.rs index 768c4fd0..2cab4be9 100644 --- a/src/macros.rs +++ b/src/macros.rs @@ -17,6 +17,53 @@ #![macro_use] +/// generates an impl fn, allowing specialization if simd is enabled +macro_rules! impl_fn { + + + // Mutable Binary + (fn $op:ident(&mut $lhs:ident, $rhs:ident:$Rhs:ty) $body:block ) => { + #[cfg(feature = "simd")] + #[inline] + default fn $op(&mut $lhs, $rhs: $Rhs) $body + + #[cfg(not(feature = "simd"))] + #[inline] + fn $op(&mut $lhs, $rhs: $Rhs) $body + }; + + // Unary + (fn $op:ident($x:ident) -> $Output:ty { $body:expr }) => { + #[cfg(feature = "simd")] + #[inline] + default fn $op(self) -> $Output { + let $x = self; $body + } + + #[cfg(not(feature = "simd"))] + #[inline] + fn $op(self) -> $Output { + let $x = self; $body + } + }; + + // Binary + (fn $op:ident($lhs:ident, $rhs:ident:$Rhs:ty) -> $Output:ty { $body:expr }) => { + #[cfg(feature = "simd")] + #[inline] + default fn $op(self, other: $Rhs) -> $Output { + let ($lhs, $rhs) = (self, other); $body + } + + #[cfg(not(feature = "simd"))] + #[inline] + fn $op(self, other: $Rhs) -> $Output { + let ($lhs, $rhs) = (self, other); $body + } + }; +} + + /// Generates a binary operator implementation for the permutations of by-ref and by-val macro_rules! impl_operator { // When it is an unary operator @@ -24,19 +71,21 @@ macro_rules! impl_operator { fn $op:ident($x:ident) -> $Output:ty { $body:expr } }) => { impl<$S: $Constraint> $Op for $Lhs { - type Output = $Output; - #[inline] - fn $op(self) -> $Output { - let $x = self; $body - } + type Output = $Output; + impl_fn!( + fn $op($x) -> $Output { + $body + } + ); } impl<'a, $S: $Constraint> $Op for &'a $Lhs { - type Output = $Output; - #[inline] - fn $op(self) -> $Output { - let $x = self; $body - } + type Output = $Output; + impl_fn!( + fn $op($x) -> $Output { + $body + } + ); } }; // When the right operand is a scalar @@ -44,19 +93,17 @@ macro_rules! impl_operator { fn $op:ident($lhs:ident, $rhs:ident) -> $Output:ty { $body:expr } }) => { impl<$S: $Constraint> $Op<$Rhs> for $Lhs { - type Output = $Output; - #[inline] - fn $op(self, other: $Rhs) -> $Output { - let ($lhs, $rhs) = (self, other); $body - } + type Output = $Output; + impl_fn!(fn $op($lhs, $rhs : $Rhs) -> $Output { + $body + }); } impl<'a, $S: $Constraint> $Op<$Rhs> for &'a $Lhs { - type Output = $Output; - #[inline] - fn $op(self, other: $Rhs) -> $Output { - let ($lhs, $rhs) = (self, other); $body - } + type Output = $Output; + impl_fn!(fn $op($lhs, $rhs : $Rhs) -> $Output { + $body + }); } }; // When the right operand is a compound type @@ -64,35 +111,34 @@ macro_rules! impl_operator { fn $op:ident($lhs:ident, $rhs:ident) -> $Output:ty { $body:expr } }) => { impl<$S: $Constraint> $Op<$Rhs> for $Lhs { - type Output = $Output; - #[inline] - fn $op(self, other: $Rhs) -> $Output { - let ($lhs, $rhs) = (self, other); $body - } + type Output = $Output; + + impl_fn!(fn $op($lhs, $rhs : $Rhs) -> $Output { + $body + }); } impl<'a, $S: $Constraint> $Op<&'a $Rhs> for $Lhs { - type Output = $Output; - #[inline] - fn $op(self, other: &'a $Rhs) -> $Output { - let ($lhs, $rhs) = (self, other); $body - } + type Output = $Output; + + impl_fn!(fn $op($lhs, $rhs : &'a $Rhs) -> $Output { + $body + }); } impl<'a, $S: $Constraint> $Op<$Rhs> for &'a $Lhs { - type Output = $Output; - #[inline] - fn $op(self, other: $Rhs) -> $Output { - let ($lhs, $rhs) = (self, other); $body - } + type Output = $Output; + impl_fn!(fn $op($lhs, $rhs : $Rhs) -> $Output { + $body + }); } impl<'a, 'b, $S: $Constraint> $Op<&'a $Rhs> for &'b $Lhs { - type Output = $Output; - #[inline] - fn $op(self, other: &'a $Rhs) -> $Output { - let ($lhs, $rhs) = (self, other); $body - } + type Output = $Output; + + impl_fn!(fn $op($lhs, $rhs : &'a $Rhs) -> $Output { + $body + }); } }; // When the left operand is a scalar @@ -100,19 +146,19 @@ macro_rules! impl_operator { 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 - } + type Output = $Output; + + impl_fn!(fn $op($lhs, $rhs : $Rhs<$S>) -> $Output { + $body + }); } 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 - } + type Output = $Output; + + impl_fn!(fn $op($lhs, $rhs : &'a $Rhs<$S>) -> $Output { + $body + }); } }; } @@ -122,8 +168,7 @@ macro_rules! impl_assignment_operator { fn $op:ident(&mut $lhs:ident, $rhs:ident) $body:block }) => { impl<$S: $Constraint + $Op<$S>> $Op<$Rhs> for $Lhs { - #[inline] - fn $op(&mut $lhs, $rhs: $Rhs) $body + impl_fn!(fn $op(&mut $lhs, $rhs : $Rhs) { $body }); } }; } @@ -255,118 +300,6 @@ macro_rules! impl_index_operators { } } -#[cfg(feature = "simd")] -macro_rules! impl_operator_default { - // When it is an unary operator - (<$S:ident: $Constraint:ident> $Op:ident for $Lhs:ty { - fn $op:ident($x:ident) -> $Output:ty { $body:expr } - }) => { - impl<$S: $Constraint> $Op for $Lhs { - type Output = $Output; - #[inline] - default fn $op(self) -> $Output { - let $x = self; $body - } - } - - impl<'a, $S: $Constraint> $Op for &'a $Lhs { - type Output = $Output; - #[inline] - default fn $op(self) -> $Output { - let $x = self; $body - } - } - }; - // When the right operand is a scalar - (<$S:ident: $Constraint:ident> $Op:ident<$Rhs:ident> for $Lhs:ty { - fn $op:ident($lhs:ident, $rhs:ident) -> $Output:ty { $body:expr } - }) => { - impl<$S: $Constraint> $Op<$Rhs> for $Lhs { - type Output = $Output; - #[inline] - default fn $op(self, other: $Rhs) -> $Output { - let ($lhs, $rhs) = (self, other); $body - } - } - - impl<'a, $S: $Constraint> $Op<$Rhs> for &'a $Lhs { - type Output = $Output; - #[inline] - default fn $op(self, other: $Rhs) -> $Output { - let ($lhs, $rhs) = (self, other); $body - } - } - }; - // When the right operand is a compound type - (<$S:ident: $Constraint:ident> $Op:ident<$Rhs:ty> for $Lhs:ty { - fn $op:ident($lhs:ident, $rhs:ident) -> $Output:ty { $body:expr } - }) => { - impl<$S: $Constraint> $Op<$Rhs> for $Lhs { - type Output = $Output; - #[inline] - default fn $op(self, other: $Rhs) -> $Output { - let ($lhs, $rhs) = (self, other); $body - } - } - - impl<'a, $S: $Constraint> $Op<&'a $Rhs> for $Lhs { - type Output = $Output; - #[inline] - default fn $op(self, other: &'a $Rhs) -> $Output { - let ($lhs, $rhs) = (self, other); $body - } - } - - impl<'a, $S: $Constraint> $Op<$Rhs> for &'a $Lhs { - type Output = $Output; - #[inline] - default fn $op(self, other: $Rhs) -> $Output { - let ($lhs, $rhs) = (self, other); $body - } - } - - impl<'a, 'b, $S: $Constraint> $Op<&'a $Rhs> for &'b $Lhs { - type Output = $Output; - #[inline] - default fn $op(self, other: &'a $Rhs) -> $Output { - let ($lhs, $rhs) = (self, other); $body - } - } - }; - // 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] - default fn $op(self, other: $Rhs<$S>) -> $Output { - let ($lhs, $rhs) = (self, other); $body - } - } - - impl<'a> $Op<&'a $Rhs<$S>> for $Lhs { - type Output = $Output; - #[inline] - default fn $op(self, other: &'a $Rhs<$S>) -> $Output { - let ($lhs, $rhs) = (self, other); $body - } - } - }; -} - -#[cfg(feature = "simd")] -macro_rules! impl_assignment_operator_default { - (<$S:ident: $Constraint:ident> $Op:ident<$Rhs:ty> for $Lhs:ty { - fn $op:ident(&mut $lhs:ident, $rhs:ident) $body:block - }) => { - impl<$S: $Constraint + $Op<$S>> $Op<$Rhs> for $Lhs { - #[inline] - default fn $op(&mut $lhs, $rhs: $Rhs) $body - } - }; -} - /// Generates a binary operator implementation for the permutations of by-ref and by-val, for simd #[cfg(feature = "simd")] macro_rules! impl_operator_simd { diff --git a/src/num.rs b/src/num.rs index 0e4eefce..fc614a9f 100644 --- a/src/num.rs +++ b/src/num.rs @@ -18,14 +18,18 @@ use approx::ApproxEq; use std::fmt; use std::ops::*; -use num_traits::{Float, Num, NumCast}; +use num_traits::{Float, Num, NumCast, Signed}; /// Base numeric types with partial ordering pub trait BaseNum: Copy + Clone + fmt::Debug + Num + NumCast + PartialOrd + AddAssign + SubAssign + MulAssign + DivAssign + RemAssign {} impl BaseNum for T where T: Copy + Clone + fmt::Debug + Num + NumCast + PartialOrd + AddAssign + SubAssign + MulAssign + DivAssign + RemAssign {} +/// Base signed types +pub trait BaseSigned: BaseNum + Signed {} + +impl BaseSigned for T where T: BaseNum + Signed {} /// Base floating point types -pub trait BaseFloat: BaseNum + Float + ApproxEq {} +pub trait BaseFloat: BaseSigned + Float + ApproxEq {} -impl BaseFloat for T where T: BaseNum + Float + ApproxEq {} +impl BaseFloat for T where T: BaseSigned + Float + ApproxEq {} diff --git a/src/quaternion.rs b/src/quaternion.rs index 5063d528..d22c6bcd 100644 --- a/src/quaternion.rs +++ b/src/quaternion.rs @@ -239,20 +239,10 @@ impl Quaternion { } } -#[cfg(not(feature = "simd"))] impl InnerSpace for Quaternion { - #[inline] - fn dot(self, other: Quaternion) -> S { - self.s * other.s + self.v.dot(other.v) - } -} - -#[cfg(feature = "simd")] -impl InnerSpace for Quaternion { - #[inline] - default fn dot(self, other: Quaternion) -> S { - self.s * other.s + self.v.dot(other.v) - } + impl_fn!(fn dot(lhs, other: Quaternion) -> S { + lhs.s * other.s + lhs.v.dot(other.v) + }); } #[cfg(feature = "simd")] @@ -287,20 +277,12 @@ impl From> for Quaternion where } } -#[cfg(not(feature = "simd"))] impl_operator!( Neg for Quaternion { fn neg(quat) -> Quaternion { Quaternion::from_sv(-quat.s, -quat.v) } }); -#[cfg(feature = "simd")] -impl_operator_default!( Neg for Quaternion { - fn neg(quat) -> Quaternion { - Quaternion::from_sv(-quat.s, -quat.v) - } -}); - #[cfg(feature = "simd")] impl_operator_simd!{ [Simdf32x4]; Neg for Quaternion { @@ -310,20 +292,12 @@ impl_operator_simd!{ } } -#[cfg(not(feature = "simd"))] impl_operator!( Mul for Quaternion { fn mul(lhs, rhs) -> Quaternion { Quaternion::from_sv(lhs.s * rhs, lhs.v * rhs) } }); -#[cfg(feature = "simd")] -impl_operator_default!( Mul for Quaternion { - fn mul(lhs, rhs) -> Quaternion { - Quaternion::from_sv(lhs.s * rhs, lhs.v * rhs) - } -}); - #[cfg(feature = "simd")] impl_operator_simd!{@rs [Simdf32x4]; Mul for Quaternion { @@ -333,16 +307,10 @@ impl_operator_simd!{@rs } } -#[cfg(not(feature = "simd"))] impl_assignment_operator!( MulAssign for Quaternion { fn mul_assign(&mut self, scalar) { self.s *= scalar; self.v *= scalar; } }); -#[cfg(feature = "simd")] -impl_assignment_operator_default!( MulAssign for Quaternion { - fn mul_assign(&mut self, scalar) { self.s *= scalar; self.v *= scalar; } -}); - #[cfg(feature = "simd")] impl MulAssign for Quaternion { fn mul_assign(&mut self, other: f32) { @@ -352,19 +320,12 @@ impl MulAssign for Quaternion { } } -#[cfg(not(feature = "simd"))] impl_operator!( Div for Quaternion { fn div(lhs, rhs) -> Quaternion { Quaternion::from_sv(lhs.s / rhs, lhs.v / rhs) } }); -#[cfg(feature = "simd")] -impl_operator_default!( Div for Quaternion { - fn div(lhs, rhs) -> Quaternion { - Quaternion::from_sv(lhs.s / rhs, lhs.v / rhs) - } -}); #[cfg(feature = "simd")] impl_operator_simd!{@rs @@ -375,16 +336,10 @@ impl_operator_simd!{@rs } } -#[cfg(not(feature = "simd"))] impl_assignment_operator!( DivAssign for Quaternion { fn div_assign(&mut self, scalar) { self.s /= scalar; self.v /= scalar; } }); -#[cfg(feature = "simd")] -impl_assignment_operator_default!( DivAssign for Quaternion { - fn div_assign(&mut self, scalar) { self.s /= scalar; self.v /= scalar; } -}); - #[cfg(feature = "simd")] impl DivAssign for Quaternion { fn div_assign(&mut self, other: f32) { @@ -413,20 +368,12 @@ impl_operator!( Mul > for Quaternion { }} }); -#[cfg(not(feature = "simd"))] impl_operator!( Add > for Quaternion { fn add(lhs, rhs) -> Quaternion { Quaternion::from_sv(lhs.s + rhs.s, lhs.v + rhs.v) } }); -#[cfg(feature = "simd")] -impl_operator_default!( Add > for Quaternion { - fn add(lhs, rhs) -> Quaternion { - Quaternion::from_sv(lhs.s + rhs.s, lhs.v + rhs.v) - } -}); - #[cfg(feature = "simd")] impl_operator_simd!{ [Simdf32x4]; Add> for Quaternion { @@ -436,16 +383,10 @@ impl_operator_simd!{ } } -#[cfg(not(feature = "simd"))] impl_assignment_operator!( AddAssign > for Quaternion { fn add_assign(&mut self, other) { self.s += other.s; self.v += other.v; } }); -#[cfg(feature = "simd")] -impl_assignment_operator_default!( AddAssign > for Quaternion { - fn add_assign(&mut self, other) { self.s += other.s; self.v += other.v; } -}); - #[cfg(feature = "simd")] impl AddAssign for Quaternion { #[inline] @@ -456,20 +397,12 @@ impl AddAssign for Quaternion { } } -#[cfg(not(feature = "simd"))] impl_operator!( Sub > for Quaternion { fn sub(lhs, rhs) -> Quaternion { Quaternion::from_sv(lhs.s - rhs.s, lhs.v - rhs.v) } }); -#[cfg(feature = "simd")] -impl_operator_default!( Sub > for Quaternion { - fn sub(lhs, rhs) -> Quaternion { - Quaternion::from_sv(lhs.s - rhs.s, lhs.v - rhs.v) - } -}); - #[cfg(feature = "simd")] impl_operator_simd!{ [Simdf32x4]; Sub> for Quaternion { @@ -479,16 +412,10 @@ impl_operator_simd!{ } } -#[cfg(not(feature = "simd"))] impl_assignment_operator!( SubAssign > for Quaternion { fn sub_assign(&mut self, other) { self.s -= other.s; self.v -= other.v; } }); -#[cfg(feature = "simd")] -impl_assignment_operator_default!( SubAssign > for Quaternion { - fn sub_assign(&mut self, other) { self.s -= other.s; self.v -= other.v; } -}); - #[cfg(feature = "simd")] impl SubAssign for Quaternion { #[inline] @@ -499,7 +426,6 @@ impl SubAssign for Quaternion { } } -#[cfg(not(feature = "simd"))] impl_operator!( Mul > for Quaternion { fn mul(lhs, rhs) -> Quaternion { Quaternion::new(lhs.s * rhs.s - lhs.v.x * rhs.v.x - lhs.v.y * rhs.v.y - lhs.v.z * rhs.v.z, @@ -509,16 +435,6 @@ impl_operator!( Mul > for Quaternion { } }); -#[cfg(feature = "simd")] -impl_operator_default!( Mul > for Quaternion { - fn mul(lhs, rhs) -> Quaternion { - Quaternion::new(lhs.s * rhs.s - lhs.v.x * rhs.v.x - lhs.v.y * rhs.v.y - lhs.v.z * rhs.v.z, - lhs.s * rhs.v.x + lhs.v.x * rhs.s + lhs.v.y * rhs.v.z - lhs.v.z * rhs.v.y, - lhs.s * rhs.v.y + lhs.v.y * rhs.s + lhs.v.z * rhs.v.x - lhs.v.x * rhs.v.z, - lhs.s * rhs.v.z + lhs.v.z * rhs.s + lhs.v.x * rhs.v.y - lhs.v.y * rhs.v.x) - } -}); - #[cfg(feature = "simd")] impl_operator_simd!{ [Simdf32x4]; Mul> for Quaternion { diff --git a/src/vector.rs b/src/vector.rs index f52232a7..9d18d3ef 100644 --- a/src/vector.rs +++ b/src/vector.rs @@ -24,7 +24,7 @@ use structure::*; use angle::Rad; use approx::ApproxEq; -use num::{BaseNum, BaseFloat}; +use num::{BaseNum, BaseFloat, BaseSigned}; #[cfg(feature = "simd")] use simd::f32x4 as Simdf32x4; @@ -180,12 +180,9 @@ macro_rules! impl_vector { type Scalar = S; } - impl> Neg for $VectorN { - type Output = $VectorN; - - #[inline] - fn neg(self) -> $VectorN { $VectorN::new($(-self.$field),+) } - } + impl_operator!( Neg for $VectorN { + fn neg(x) -> $VectorN { $VectorN::new($(-x.$field),+) } + }); impl ApproxEq for $VectorN { type Epsilon = S::Epsilon; @@ -259,31 +256,32 @@ macro_rules! impl_vector { }); impl ElementWise for $VectorN { - #[inline] fn add_element_wise(self, rhs: $VectorN) -> $VectorN { $VectorN::new($(self.$field + rhs.$field),+) } - #[inline] fn sub_element_wise(self, rhs: $VectorN) -> $VectorN { $VectorN::new($(self.$field - rhs.$field),+) } - #[inline] fn mul_element_wise(self, rhs: $VectorN) -> $VectorN { $VectorN::new($(self.$field * rhs.$field),+) } - #[inline] fn div_element_wise(self, rhs: $VectorN) -> $VectorN { $VectorN::new($(self.$field / rhs.$field),+) } - #[inline] fn rem_element_wise(self, rhs: $VectorN) -> $VectorN { $VectorN::new($(self.$field % rhs.$field),+) } - - #[inline] fn add_assign_element_wise(&mut self, rhs: $VectorN) { $(self.$field += rhs.$field);+ } - #[inline] fn sub_assign_element_wise(&mut self, rhs: $VectorN) { $(self.$field -= rhs.$field);+ } - #[inline] fn mul_assign_element_wise(&mut self, rhs: $VectorN) { $(self.$field *= rhs.$field);+ } - #[inline] fn div_assign_element_wise(&mut self, rhs: $VectorN) { $(self.$field /= rhs.$field);+ } - #[inline] fn rem_assign_element_wise(&mut self, rhs: $VectorN) { $(self.$field %= rhs.$field);+ } + + impl_fn!(fn add_element_wise(lhs, rhs: $VectorN) -> $VectorN { $VectorN::new($(lhs.$field + rhs.$field),+) }); + impl_fn!(fn sub_element_wise(lhs, rhs: $VectorN) -> $VectorN { $VectorN::new($(lhs.$field - rhs.$field),+) }); + impl_fn!(fn mul_element_wise(lhs, rhs: $VectorN) -> $VectorN { $VectorN::new($(lhs.$field * rhs.$field),+) }); + impl_fn!(fn div_element_wise(lhs, rhs: $VectorN) -> $VectorN { $VectorN::new($(lhs.$field / rhs.$field),+) }); + impl_fn!(fn rem_element_wise(lhs, rhs: $VectorN) -> $VectorN { $VectorN::new($(lhs.$field % rhs.$field),+) }); + + impl_fn!(fn add_assign_element_wise(&mut self, rhs: $VectorN) { $(self.$field += rhs.$field);+ }); + impl_fn!(fn sub_assign_element_wise(&mut self, rhs: $VectorN) { $(self.$field -= rhs.$field);+ }); + impl_fn!(fn mul_assign_element_wise(&mut self, rhs: $VectorN) { $(self.$field *= rhs.$field);+ }); + impl_fn!(fn div_assign_element_wise(&mut self, rhs: $VectorN) { $(self.$field /= rhs.$field);+ }); + impl_fn!(fn rem_assign_element_wise(&mut self, rhs: $VectorN) { $(self.$field %= rhs.$field);+ }); } impl ElementWise for $VectorN { - #[inline] fn add_element_wise(self, rhs: S) -> $VectorN { $VectorN::new($(self.$field + rhs),+) } - #[inline] fn sub_element_wise(self, rhs: S) -> $VectorN { $VectorN::new($(self.$field - rhs),+) } - #[inline] fn mul_element_wise(self, rhs: S) -> $VectorN { $VectorN::new($(self.$field * rhs),+) } - #[inline] fn div_element_wise(self, rhs: S) -> $VectorN { $VectorN::new($(self.$field / rhs),+) } - #[inline] fn rem_element_wise(self, rhs: S) -> $VectorN { $VectorN::new($(self.$field % rhs),+) } - - #[inline] fn add_assign_element_wise(&mut self, rhs: S) { $(self.$field += rhs);+ } - #[inline] fn sub_assign_element_wise(&mut self, rhs: S) { $(self.$field -= rhs);+ } - #[inline] fn mul_assign_element_wise(&mut self, rhs: S) { $(self.$field *= rhs);+ } - #[inline] fn div_assign_element_wise(&mut self, rhs: S) { $(self.$field /= rhs);+ } - #[inline] fn rem_assign_element_wise(&mut self, rhs: S) { $(self.$field %= rhs);+ } + impl_fn!(fn add_element_wise(lhs, rhs: S) -> $VectorN { $VectorN::new($(lhs.$field + rhs),+) }); + impl_fn!(fn sub_element_wise(lhs, rhs: S) -> $VectorN { $VectorN::new($(lhs.$field - rhs),+) }); + impl_fn!(fn mul_element_wise(lhs, rhs: S) -> $VectorN { $VectorN::new($(lhs.$field * rhs),+) }); + impl_fn!(fn div_element_wise(lhs, rhs: S) -> $VectorN { $VectorN::new($(lhs.$field / rhs),+) }); + impl_fn!(fn rem_element_wise(lhs, rhs: S) -> $VectorN { $VectorN::new($(lhs.$field % rhs),+) }); + + impl_fn!(fn add_assign_element_wise(&mut self, rhs: S) { $(self.$field += rhs);+ }); + impl_fn!(fn sub_assign_element_wise(&mut self, rhs: S) { $(self.$field -= rhs);+ }); + impl_fn!(fn mul_assign_element_wise(&mut self, rhs: S) { $(self.$field *= rhs);+ }); + impl_fn!(fn div_assign_element_wise(&mut self, rhs: S) { $(self.$field /= rhs);+ }); + impl_fn!(fn rem_assign_element_wise(&mut self, rhs: S) { $(self.$field %= rhs);+ }); } impl_scalar_ops!($VectorN { $($field),+ }); @@ -307,227 +305,6 @@ macro_rules! impl_vector { } } -// Utility macro for generating associated functions for the vectors -// mainly duplication -#[cfg(feature = "simd")] -macro_rules! impl_vector_default { - ($VectorN:ident { $($field:ident),+ }, $n:expr, $constructor:ident) => { - impl $VectorN { - /// Construct a new vector, using the provided values. - #[inline] - pub fn new($($field: S),+) -> $VectorN { - $VectorN { $($field: $field),+ } - } - } - - /// The short constructor. - #[inline] - pub fn $constructor($($field: S),+) -> $VectorN { - $VectorN::new($($field),+) - } - - impl $VectorN { - /// Component-wise casting to another type. - #[inline] - pub fn cast(&self) -> $VectorN { - $VectorN { $($field: NumCast::from(self.$field).unwrap()),+ } - } - } - - impl MetricSpace for $VectorN { - type Metric = S; - - #[inline] - fn distance2(self, other: Self) -> S { - (other - self).magnitude2() - } - } - - impl Array for $VectorN { - type Element = S; - - #[inline] - fn len() -> usize { - $n - } - - #[inline] - fn from_value(scalar: S) -> $VectorN { - $VectorN { $($field: scalar),+ } - } - - #[inline] - fn sum(self) -> S where S: Add { - fold_array!(add, { $(self.$field),+ }) - } - - #[inline] - fn product(self) -> S where S: Mul { - fold_array!(mul, { $(self.$field),+ }) - } - } - - impl Zero for $VectorN { - #[inline] - fn zero() -> $VectorN { - $VectorN::from_value(S::zero()) - } - - #[inline] - fn is_zero(&self) -> bool { - *self == $VectorN::zero() - } - } - - impl iter::Sum for $VectorN { - #[inline] - fn sum>(iter: I) -> Self { - iter.fold(Self::zero(), Add::add) - } - } - - impl<'a, S: 'a + BaseNum> iter::Sum<&'a Self> for $VectorN { - #[inline] - fn sum>(iter: I) -> Self { - iter.fold(Self::zero(), Add::add) - } - } - - impl VectorSpace for $VectorN { - type Scalar = S; - } - - impl> Neg for $VectorN { - type Output = $VectorN; - - #[inline] - default fn neg(self) -> $VectorN { $VectorN::new($(-self.$field),+) } - } - - impl ApproxEq for $VectorN { - type Epsilon = S::Epsilon; - - #[inline] - fn default_epsilon() -> S::Epsilon { - S::default_epsilon() - } - - #[inline] - fn default_max_relative() -> S::Epsilon { - S::default_max_relative() - } - - #[inline] - fn default_max_ulps() -> u32 { - S::default_max_ulps() - } - - #[inline] - fn relative_eq(&self, other: &Self, epsilon: S::Epsilon, max_relative: S::Epsilon) -> bool { - $(S::relative_eq(&self.$field, &other.$field, epsilon, max_relative))&&+ - } - - #[inline] - fn ulps_eq(&self, other: &Self, epsilon: S::Epsilon, max_ulps: u32) -> bool { - $(S::ulps_eq(&self.$field, &other.$field, epsilon, max_ulps))&&+ - } - } - - impl Rand for $VectorN { - #[inline] - fn rand(rng: &mut R) -> $VectorN { - $VectorN { $($field: rng.gen()),+ } - } - } - - impl_operator_default!( Add<$VectorN > for $VectorN { - fn add(lhs, rhs) -> $VectorN { $VectorN::new($(lhs.$field + rhs.$field),+) } - }); - - impl_assignment_operator_default!( AddAssign<$VectorN > for $VectorN { - fn add_assign(&mut self, other) { $(self.$field += other.$field);+ } - }); - - impl_operator_default!( Sub<$VectorN > for $VectorN { - fn sub(lhs, rhs) -> $VectorN { $VectorN::new($(lhs.$field - rhs.$field),+) } - }); - - impl_assignment_operator_default!( SubAssign<$VectorN > for $VectorN { - fn sub_assign(&mut self, other) { $(self.$field -= other.$field);+ } - }); - - impl_operator_default!( Mul for $VectorN { - fn mul(vector, scalar) -> $VectorN { $VectorN::new($(vector.$field * scalar),+) } - }); - - impl_assignment_operator_default!( MulAssign for $VectorN { - fn mul_assign(&mut self, scalar) { $(self.$field *= scalar);+ } - }); - - impl_operator_default!( Div for $VectorN { - fn div(vector, scalar) -> $VectorN { $VectorN::new($(vector.$field / scalar),+) } - }); - - impl_assignment_operator_default!( DivAssign for $VectorN { - fn div_assign(&mut self, scalar) { $(self.$field /= scalar);+ } - }); - - impl_operator!( Rem for $VectorN { - fn rem(vector, scalar) -> $VectorN { $VectorN::new($(vector.$field % scalar),+) } - }); - impl_assignment_operator!( RemAssign for $VectorN { - fn rem_assign(&mut self, scalar) { $(self.$field %= scalar);+ } - }); - - impl ElementWise for $VectorN { - #[inline] default fn add_element_wise(self, rhs: $VectorN) -> $VectorN { $VectorN::new($(self.$field + rhs.$field),+) } - #[inline] default fn sub_element_wise(self, rhs: $VectorN) -> $VectorN { $VectorN::new($(self.$field - rhs.$field),+) } - #[inline] default fn mul_element_wise(self, rhs: $VectorN) -> $VectorN { $VectorN::new($(self.$field * rhs.$field),+) } - #[inline] default fn div_element_wise(self, rhs: $VectorN) -> $VectorN { $VectorN::new($(self.$field / rhs.$field),+) } - #[inline] fn rem_element_wise(self, rhs: $VectorN) -> $VectorN { $VectorN::new($(self.$field % rhs.$field),+) } - - #[inline] default fn add_assign_element_wise(&mut self, rhs: $VectorN) { $(self.$field += rhs.$field);+ } - #[inline] default fn sub_assign_element_wise(&mut self, rhs: $VectorN) { $(self.$field -= rhs.$field);+ } - #[inline] default fn mul_assign_element_wise(&mut self, rhs: $VectorN) { $(self.$field *= rhs.$field);+ } - #[inline] default fn div_assign_element_wise(&mut self, rhs: $VectorN) { $(self.$field /= rhs.$field);+ } - #[inline] fn rem_assign_element_wise(&mut self, rhs: $VectorN) { $(self.$field %= rhs.$field);+ } - } - - impl ElementWise for $VectorN { - #[inline] default fn add_element_wise(self, rhs: S) -> $VectorN { $VectorN::new($(self.$field + rhs),+) } - #[inline] default fn sub_element_wise(self, rhs: S) -> $VectorN { $VectorN::new($(self.$field - rhs),+) } - #[inline] default fn mul_element_wise(self, rhs: S) -> $VectorN { $VectorN::new($(self.$field * rhs),+) } - #[inline] default fn div_element_wise(self, rhs: S) -> $VectorN { $VectorN::new($(self.$field / rhs),+) } - #[inline] fn rem_element_wise(self, rhs: S) -> $VectorN { $VectorN::new($(self.$field % rhs),+) } - - #[inline] default fn add_assign_element_wise(&mut self, rhs: S) { $(self.$field += rhs);+ } - #[inline] default fn sub_assign_element_wise(&mut self, rhs: S) { $(self.$field -= rhs);+ } - #[inline] default fn mul_assign_element_wise(&mut self, rhs: S) { $(self.$field *= rhs);+ } - #[inline] default fn div_assign_element_wise(&mut self, rhs: S) { $(self.$field /= rhs);+ } - #[inline] fn rem_assign_element_wise(&mut self, rhs: S) { $(self.$field %= rhs);+ } - } - - impl_scalar_ops!($VectorN { $($field),+ }); - impl_scalar_ops!($VectorN { $($field),+ }); - impl_scalar_ops!($VectorN { $($field),+ }); - impl_scalar_ops_default!($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_default!($VectorN { $($field),+ }); - impl_scalar_ops!($VectorN { $($field),+ }); - impl_scalar_ops_default!($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); - impl_index_operators!($VectorN, $n, [S], RangeFrom); - impl_index_operators!($VectorN, $n, [S], RangeFull); - } -} - macro_rules! impl_scalar_ops { ($VectorN:ident<$S:ident> { $($field:ident),+ }) => { impl_operator!(Mul<$VectorN<$S>> for $S { @@ -542,28 +319,10 @@ macro_rules! impl_scalar_ops { }; } -#[cfg(feature = "simd")] -macro_rules! impl_scalar_ops_default { - ($VectorN:ident<$S:ident> { $($field:ident),+ }) => { - impl_operator_default!(Mul<$VectorN<$S>> for $S { - fn mul(scalar, vector) -> $VectorN<$S> { $VectorN::new($(scalar * vector.$field),+) } - }); - impl_operator_default!(Div<$VectorN<$S>> for $S { - fn div(scalar, vector) -> $VectorN<$S> { $VectorN::new($(scalar / vector.$field),+) } - }); - impl_operator_default!(Rem<$VectorN<$S>> for $S { - fn rem(scalar, vector) -> $VectorN<$S> { $VectorN::new($(scalar % vector.$field),+) } - }); - }; -} - impl_vector!(Vector1 { x }, 1, vec1); impl_vector!(Vector2 { x, y }, 2, vec2); impl_vector!(Vector3 { x, y, z }, 3, vec3); -#[cfg(not(feature = "simd"))] impl_vector!(Vector4 { x, y, z, w }, 4, vec4); -#[cfg(feature = "simd")] -impl_vector_default!(Vector4 { x, y, z, w }, 4, vec4); impl_fixed_array_conversions!(Vector1 { x: 0 }, 1); impl_fixed_array_conversions!(Vector2 { x: 0, y: 1 }, 2);