Standardise macro use for code generation

This moves lots of the common code generation patterns into a macros module. In doing so, the code can be greatly reduced in size.
This commit is contained in:
Brendan Zabarauskas 2015-12-12 22:17:03 +11:00
parent 80a89581ef
commit 577eafa654
5 changed files with 348 additions and 748 deletions

View file

@ -55,6 +55,8 @@ pub use rust_num::{One, Zero, one, zero};
// Modules // Modules
mod macros;
mod array; mod array;
mod matrix; mod matrix;

203
src/macros.rs Normal file
View file

@ -0,0 +1,203 @@
// Copyright 2013-2014 The CGMath Developers. For a full listing of the authors,
// refer to the Cargo.toml file at the top-level directory of this distribution.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//! Utility macros for code generation
#![macro_use]
/// Generates a binary operator implementation for the permutations of by-ref and by-val
macro_rules! impl_binary_operator {
// When the right operand is a scalar
(<$S:ident: $Constraint:ident> $Binop:ident<$Rhs:ident> for $Lhs:ty {
fn $binop:ident($lhs:ident, $rhs:ident) -> $Output:ty { $body:expr }
}) => {
impl<$S: $Constraint> $Binop<$Rhs> for $Lhs {
type Output = $Output;
#[inline]
fn $binop(self, other: $Rhs) -> $Output {
let ($lhs, $rhs) = (self, other); $body
}
}
impl<'a, $S: $Constraint> $Binop<$Rhs> for &'a $Lhs {
type Output = $Output;
#[inline]
fn $binop(self, other: $Rhs) -> $Output {
let ($lhs, $rhs) = (self, other); $body
}
}
};
// When the right operand is a compound type
(<$S:ident: $Constraint:ident> $Binop:ident<$Rhs:ty> for $Lhs:ty {
fn $binop:ident($lhs:ident, $rhs:ident) -> $Output:ty { $body:expr }
}) => {
impl<$S: $Constraint> $Binop<$Rhs> for $Lhs {
type Output = $Output;
#[inline]
fn $binop(self, other: $Rhs) -> $Output {
let ($lhs, $rhs) = (self, other); $body
}
}
impl<'a, $S: $Constraint> $Binop<&'a $Rhs> for $Lhs {
type Output = $Output;
#[inline]
fn $binop(self, other: &'a $Rhs) -> $Output {
let ($lhs, $rhs) = (self, other); $body
}
}
impl<'a, $S: $Constraint> $Binop<$Rhs> for &'a $Lhs {
type Output = $Output;
#[inline]
fn $binop(self, other: $Rhs) -> $Output {
let ($lhs, $rhs) = (self, other); $body
}
}
impl<'a, 'b, $S: $Constraint> $Binop<&'a $Rhs> for &'b $Lhs {
type Output = $Output;
#[inline]
fn $binop(self, other: &'a $Rhs) -> $Output {
let ($lhs, $rhs) = (self, other); $body
}
}
};
}
macro_rules! fold_array {
(&$method:ident, { $x:expr, $y:expr }) => { $x.$method(&$y) };
(&$method:ident, { $x:expr, $y:expr, $z:expr }) => { $x.$method(&$y).$method(&$z) };
(&$method:ident, { $x:expr, $y:expr, $z:expr, $w:expr }) => { $x.$method(&$y).$method(&$z).$method(&$w) };
($method:ident, { $x:expr, $y:expr }) => { $x.$method($y) };
($method:ident, { $x:expr, $y:expr, $z:expr }) => { $x.$method($y).$method($z) };
($method:ident, { $x:expr, $y:expr, $z:expr, $w:expr }) => { $x.$method($y).$method($z).$method($w) };
}
/// Generate array conversion implementations for a compound array type
macro_rules! impl_fixed_array_conversions {
($ArrayN:ident <$S:ident> { $($field:ident : $index:expr),+ }, $n:expr) => {
impl<$S> Into<[$S; $n]> for $ArrayN<$S> {
#[inline]
fn into(self) -> [$S; $n] {
match self { $ArrayN { $($field),+ } => [$($field),+] }
}
}
impl<$S> AsRef<[$S; $n]> for $ArrayN<$S> {
#[inline]
fn as_ref(&self) -> &[$S; $n] {
unsafe { mem::transmute(self) }
}
}
impl<$S> AsMut<[$S; $n]> for $ArrayN<$S> {
#[inline]
fn as_mut(&mut self) -> &mut [$S; $n] {
unsafe { mem::transmute(self) }
}
}
impl<$S: Clone> From<[$S; $n]> for $ArrayN<$S> {
#[inline]
fn from(v: [$S; $n]) -> $ArrayN<$S> {
// We need to use a clone here because we can't pattern match on arrays yet
$ArrayN { $($field: v[$index].clone()),+ }
}
}
impl<'a, $S> From<&'a [$S; $n]> for &'a $ArrayN<$S> {
#[inline]
fn from(v: &'a [$S; $n]) -> &'a $ArrayN<$S> {
unsafe { mem::transmute(v) }
}
}
impl<'a, $S> From<&'a mut [$S; $n]> for &'a mut $ArrayN<$S> {
#[inline]
fn from(v: &'a mut [$S; $n]) -> &'a mut $ArrayN<$S> {
unsafe { mem::transmute(v) }
}
}
}
}
/// Generate homogeneous tuple conversion implementations for a compound array type
macro_rules! impl_tuple_conversions {
($ArrayN:ident <$S:ident> { $($field:ident),+ }, $Tuple:ty) => {
impl<$S> Into<$Tuple> for $ArrayN<$S> {
#[inline]
fn into(self) -> $Tuple {
match self { $ArrayN { $($field),+ } => ($($field),+) }
}
}
impl<$S> AsRef<$Tuple> for $ArrayN<$S> {
#[inline]
fn as_ref(&self) -> &$Tuple {
unsafe { mem::transmute(self) }
}
}
impl<$S> AsMut<$Tuple> for $ArrayN<$S> {
#[inline]
fn as_mut(&mut self) -> &mut $Tuple {
unsafe { mem::transmute(self) }
}
}
impl<$S> From<$Tuple> for $ArrayN<$S> {
#[inline]
fn from(v: $Tuple) -> $ArrayN<$S> {
match v { ($($field),+) => $ArrayN { $($field: $field),+ } }
}
}
impl<'a, $S> From<&'a $Tuple> for &'a $ArrayN<$S> {
#[inline]
fn from(v: &'a $Tuple) -> &'a $ArrayN<$S> {
unsafe { mem::transmute(v) }
}
}
impl<'a, $S> From<&'a mut $Tuple> for &'a mut $ArrayN<$S> {
#[inline]
fn from(v: &'a mut $Tuple) -> &'a mut $ArrayN<$S> {
unsafe { mem::transmute(v) }
}
}
}
}
/// Generates index operators for a compound type
macro_rules! impl_index_operators {
($VectorN:ident<$S:ident>, $n:expr, $Output:ty, $I:ty) => {
impl<$S> Index<$I> for $VectorN<$S> {
type Output = $Output;
#[inline]
fn index<'a>(&'a self, i: $I) -> &'a $Output {
let v: &[$S; $n] = self.as_ref(); &v[i]
}
}
impl<$S> IndexMut<$I> for $VectorN<$S> {
#[inline]
fn index_mut<'a>(&'a mut self, i: $I) -> &'a mut $Output {
let v: &mut [$S; $n] = self.as_mut(); &mut v[i]
}
}
}
}

View file

@ -122,476 +122,99 @@ pub trait Point: Copy + Clone where
/// This is a weird one, but its useful for plane calculations. /// This is a weird one, but its useful for plane calculations.
fn dot(self, v: Self::Vector) -> Self::Scalar; fn dot(self, v: Self::Vector) -> Self::Scalar;
#[must_use]
fn min(self, p: Self) -> Self;
#[must_use]
fn max(self, p: Self) -> Self;
} }
impl<S: BaseNum> Array for Point2<S> { macro_rules! impl_point {
($PointN:ident { $($field:ident),+ }, $VectorN:ident, $n:expr) => {
impl<S: BaseNum> Array for $PointN<S> {
type Element = S; type Element = S;
fn sum(self) -> S { #[inline] fn sum(self) -> S { fold_array!(add, { $(self.$field),+ }) }
self.x + self.y #[inline] fn product(self) -> S { fold_array!(mul, { $(self.$field),+ }) }
#[inline] fn min(self) -> S { fold_array!(partial_min, { $(self.$field),+ }) }
#[inline] fn max(self) -> S { fold_array!(partial_max, { $(self.$field),+ }) }
} }
fn product(self) -> S { impl<S: BaseNum> Point for $PointN<S> {
self.x * self.y
}
fn min(self) -> S {
self.x.partial_min(self.y)
}
fn max(self) -> S {
self.x.partial_max(self.y)
}
}
impl<S: BaseNum> Point for Point2<S> {
type Scalar = S; type Scalar = S;
type Vector = Vector2<S>; type Vector = $VectorN<S>;
#[inline] #[inline]
fn origin() -> Point2<S> { fn origin() -> $PointN<S> {
Point2::new(S::zero(), S::zero()) $PointN { $($field: S::zero()),+ }
} }
#[inline] #[inline]
fn from_vec(v: Vector2<S>) -> Point2<S> { fn from_vec(v: $VectorN<S>) -> $PointN<S> {
Point2::new(v.x, v.y) $PointN::new($(v.$field),+)
} }
#[inline] #[inline]
fn to_vec(self) -> Vector2<S> { fn to_vec(self) -> $VectorN<S> {
Vector2::new(self.x, self.y) $VectorN::new($(self.$field),+)
} }
#[inline] fn mul_s(self, scalar: S) -> Point2<S> { self * scalar } #[inline] fn mul_s(self, scalar: S) -> $PointN<S> { self * scalar }
#[inline] fn div_s(self, scalar: S) -> Point2<S> { self / scalar } #[inline] fn div_s(self, scalar: S) -> $PointN<S> { self / scalar }
#[inline] fn rem_s(self, scalar: S) -> Point2<S> { self % scalar } #[inline] fn rem_s(self, scalar: S) -> $PointN<S> { self % scalar }
#[inline] fn add_v(self, v: Vector2<S>) -> Point2<S> { self + v } #[inline] fn add_v(self, v: $VectorN<S>) -> $PointN<S> { self + v }
#[inline] fn sub_p(self, p: Point2<S>) -> Vector2<S> { self - p } #[inline] fn sub_p(self, p: $PointN<S>) -> $VectorN<S> { self - p }
#[inline] fn mul_self_s(&mut self, scalar: S) { *self = *self * scalar; }
#[inline] fn div_self_s(&mut self, scalar: S) { *self = *self / scalar; }
#[inline] fn rem_self_s(&mut self, scalar: S) { *self = *self % scalar; }
#[inline] fn add_self_v(&mut self, vector: $VectorN<S>) { *self = *self + vector; }
#[inline] #[inline]
fn mul_self_s(&mut self, scalar: S) { fn dot(self, v: $VectorN<S>) -> S {
self.x = self.x * scalar; $VectorN::new($(self.$field * v.$field),+).sum()
self.y = self.y * scalar;
}
#[inline]
fn div_self_s(&mut self, scalar: S) {
self.x = self.x / scalar;
self.y = self.y / scalar;
}
#[inline]
fn rem_self_s(&mut self, scalar: S) {
self.x = self.x % scalar;
self.y = self.y % scalar;
}
#[inline]
fn add_self_v(&mut self, v: Vector2<S>) {
self.x = self.x + v.x;
self.y = self.y + v.y;
}
#[inline]
fn dot(self, v: Vector2<S>) -> S {
self.x * v.x +
self.y * v.y
}
#[inline]
fn min(self, p: Point2<S>) -> Point2<S> {
Point2::new(self.x.partial_min(p.x), self.y.partial_min(p.y))
}
#[inline]
fn max(self, p: Point2<S>) -> Point2<S> {
Point2::new(self.x.partial_max(p.x), self.y.partial_max(p.y))
} }
} }
impl<S: BaseFloat> ApproxEq for Point2<S> { impl<S: BaseFloat> ApproxEq for $PointN<S> {
type Epsilon = S; type Epsilon = S;
#[inline] #[inline]
fn approx_eq_eps(&self, other: &Point2<S>, epsilon: &S) -> bool { fn approx_eq_eps(&self, other: &$PointN<S>, epsilon: &S) -> bool {
self.x.approx_eq_eps(&other.x, epsilon) && $(self.$field.approx_eq_eps(&other.$field, epsilon))&&+
self.y.approx_eq_eps(&other.y, epsilon)
} }
} }
impl<S: BaseNum> Array for Point3<S> { impl_binary_operator!(<S: BaseNum> Add<$VectorN<S> > for $PointN<S> {
type Element = S; fn add(lhs, rhs) -> $PointN<S> { $PointN::new($(lhs.$field + rhs.$field),+) }
});
fn sum(self) -> S { impl_binary_operator!(<S: BaseNum> Sub<$PointN<S> > for $PointN<S> {
self.x + self.y + self.z fn sub(lhs, rhs) -> $VectorN<S> { $VectorN::new($(lhs.$field - rhs.$field),+) }
} });
fn product(self) -> S {
self.x * self.y * self.z
}
fn min(self) -> S {
self.x.partial_min(self.y).partial_min(self.z)
}
fn max(self) -> S {
self.x.partial_max(self.y).partial_max(self.z)
}
}
impl<S: BaseNum> Point for Point3<S> {
type Scalar = S;
type Vector = Vector3<S>;
#[inline]
fn origin() -> Point3<S> {
Point3::new(S::zero(), S::zero(), S::zero())
}
#[inline]
fn from_vec(v: Vector3<S>) -> Point3<S> {
Point3::new(v.x, v.y, v.z)
}
#[inline]
fn to_vec(self) -> Vector3<S> {
Vector3::new(self.x, self.y, self.z)
}
#[inline] fn mul_s(self, scalar: S) -> Point3<S> { self * scalar }
#[inline] fn div_s(self, scalar: S) -> Point3<S> { self / scalar }
#[inline] fn rem_s(self, scalar: S) -> Point3<S> { self % scalar }
#[inline] fn add_v(self, v: Vector3<S>) -> Point3<S> { self + v }
#[inline] fn sub_p(self, p: Point3<S>) -> Vector3<S> { self - p }
#[inline]
fn mul_self_s(&mut self, scalar: S) {
self.x = self.x * scalar;
self.y = self.y * scalar;
self.z = self.z * scalar;
}
#[inline]
fn div_self_s(&mut self, scalar: S) {
self.x = self.x / scalar;
self.y = self.y / scalar;
self.z = self.z / scalar;
}
#[inline]
fn rem_self_s(&mut self, scalar: S) {
self.x = self.x % scalar;
self.y = self.y % scalar;
self.z = self.z % scalar;
}
#[inline]
fn add_self_v(&mut self, v: Vector3<S>) {
self.x = self.x + v.x;
self.y = self.y + v.y;
self.z = self.z + v.z;
}
#[inline]
fn dot(self, v: Vector3<S>) -> S {
self.x * v.x +
self.y * v.y +
self.z * v.z
}
#[inline]
fn min(self, p: Point3<S>) -> Point3<S> {
Point3::new(self.x.partial_min(p.x), self.y.partial_min(p.y), self.z.partial_min(p.z))
}
#[inline]
fn max(self, p: Point3<S>) -> Point3<S> {
Point3::new(self.x.partial_max(p.x), self.y.partial_max(p.y), self.z.partial_max(p.z))
}
}
impl<S: BaseFloat> ApproxEq for Point3<S> {
type Epsilon = S;
#[inline]
fn approx_eq_eps(&self, other: &Point3<S>, epsilon: &S) -> bool {
self.x.approx_eq_eps(&other.x, epsilon) &&
self.y.approx_eq_eps(&other.y, epsilon) &&
self.z.approx_eq_eps(&other.z, epsilon)
}
}
macro_rules! impl_operators {
($PointN:ident { $($field:ident),+ }, $VectorN:ident) => {
impl<S: BaseNum> Mul<S> for $PointN<S> {
type Output = $PointN<S>;
#[inline]
fn mul(self, scalar: S) -> $PointN<S> {
$PointN::new($(self.$field * scalar),+)
}
}
impl<S: BaseNum> Div<S> for $PointN<S> {
type Output = $PointN<S>;
#[inline]
fn div(self, scalar: S) -> $PointN<S> {
$PointN::new($(self.$field / scalar),+)
}
}
impl<S: BaseNum> Rem<S> for $PointN<S> {
type Output = $PointN<S>;
#[inline]
fn rem(self, scalar: S) -> $PointN<S> {
$PointN::new($(self.$field % scalar),+)
}
}
impl<'a, S: BaseNum> Mul<S> for &'a $PointN<S> {
type Output = $PointN<S>;
#[inline]
fn mul(self, scalar: S) -> $PointN<S> {
$PointN::new($(self.$field * scalar),+)
}
}
impl<'a, S: BaseNum> Div<S> for &'a $PointN<S> {
type Output = $PointN<S>;
#[inline]
fn div(self, scalar: S) -> $PointN<S> {
$PointN::new($(self.$field / scalar),+)
}
}
impl<'a, S: BaseNum> Rem<S> for &'a $PointN<S> {
type Output = $PointN<S>;
#[inline]
fn rem(self, scalar: S) -> $PointN<S> {
$PointN::new($(self.$field % scalar),+)
}
}
impl<S: BaseNum> Add<$VectorN<S>> for $PointN<S> {
type Output = $PointN<S>;
#[inline]
fn add(self, v: $VectorN<S>) -> $PointN<S> {
$PointN::new($(self.$field + v.$field),+)
}
}
impl<S: BaseNum> Sub<$PointN<S>> for $PointN<S> {
type Output = $VectorN<S>;
#[inline]
fn sub(self, p: $PointN<S>) -> $VectorN<S> {
$VectorN::new($(self.$field - p.$field),+)
}
}
impl<'a, S: BaseNum> Add<&'a $VectorN<S>> for $PointN<S> {
type Output = $PointN<S>;
#[inline] impl_binary_operator!(<S: BaseNum> Mul<S> for $PointN<S> {
fn add(self, v: &'a $VectorN<S>) -> $PointN<S> { fn mul(point, scalar) -> $PointN<S> { $PointN::new($(point.$field * scalar),+) }
$PointN::new($(self.$field + v.$field),+) });
}
}
impl<'a, S: BaseNum> Sub<&'a $PointN<S>> for $PointN<S> {
type Output = $VectorN<S>;
#[inline]
fn sub(self, p: &'a $PointN<S>) -> $VectorN<S> {
$VectorN::new($(self.$field - p.$field),+)
}
}
impl<'a, S: BaseNum> Add<$VectorN<S>> for &'a $PointN<S> {
type Output = $PointN<S>;
#[inline]
fn add(self, v: $VectorN<S>) -> $PointN<S> {
$PointN::new($(self.$field + v.$field),+)
}
}
impl<'a, S: BaseNum> Sub<$PointN<S>> for &'a $PointN<S> { impl_binary_operator!(<S: BaseNum> Div<S> for $PointN<S> {
type Output = $VectorN<S>; fn div(point, scalar) -> $PointN<S> { $PointN::new($(point.$field / scalar),+) }
});
#[inline] impl_binary_operator!(<S: BaseNum> Rem<S> for $PointN<S> {
fn sub(self, p: $PointN<S>) -> $VectorN<S> { fn rem(point, scalar) -> $PointN<S> { $PointN::new($(point.$field % scalar),+) }
$VectorN::new($(self.$field - p.$field),+) });
}
}
impl<'a, 'b, S: BaseNum> Add<&'a $VectorN<S>> for &'b $PointN<S> { impl_index_operators!($PointN<S>, $n, S, usize);
type Output = $PointN<S>; impl_index_operators!($PointN<S>, $n, [S], Range<usize>);
impl_index_operators!($PointN<S>, $n, [S], RangeTo<usize>);
#[inline] impl_index_operators!($PointN<S>, $n, [S], RangeFrom<usize>);
fn add(self, v: &'a $VectorN<S>) -> $PointN<S> { impl_index_operators!($PointN<S>, $n, [S], RangeFull);
$PointN::new($(self.$field + v.$field),+)
} }
} }
impl<'a, 'b, S: BaseNum> Sub<&'a $PointN<S>> for &'b $PointN<S> { impl_point!(Point2 { x, y }, Vector2, 2);
type Output = $VectorN<S>; impl_point!(Point3 { x, y, z }, Vector3, 3);
#[inline]
fn sub(self, p: &'a $PointN<S>) -> $VectorN<S> {
$VectorN::new($(self.$field - p.$field),+)
}
}
}
}
impl_operators!(Point2 { x, y }, Vector2); impl_fixed_array_conversions!(Point2<S> { x: 0, y: 1 }, 2);
impl_operators!(Point3 { x, y, z }, Vector3); impl_fixed_array_conversions!(Point3<S> { x: 0, y: 1, z: 2 }, 3);
macro_rules! fixed_array_conversions {
($PointN:ident <$S:ident> { $($field:ident : $index:expr),+ }, $n:expr) => {
impl<$S> Into<[$S; $n]> for $PointN<$S> {
#[inline]
fn into(self) -> [$S; $n] {
match self { $PointN { $($field),+ } => [$($field),+] }
}
}
impl<$S> AsRef<[$S; $n]> for $PointN<$S> {
#[inline]
fn as_ref(&self) -> &[$S; $n] {
unsafe { mem::transmute(self) }
}
}
impl<$S> AsMut<[$S; $n]> for $PointN<$S> {
#[inline]
fn as_mut(&mut self) -> &mut [$S; $n] {
unsafe { mem::transmute(self) }
}
}
impl<$S: Clone> From<[$S; $n]> for $PointN<$S> {
#[inline]
fn from(v: [$S; $n]) -> $PointN<$S> {
// We need to use a clone here because we can't pattern match on arrays yet
$PointN { $($field: v[$index].clone()),+ }
}
}
impl<'a, $S> From<&'a [$S; $n]> for &'a $PointN<$S> {
#[inline]
fn from(v: &'a [$S; $n]) -> &'a $PointN<$S> {
unsafe { mem::transmute(v) }
}
}
impl<'a, $S> From<&'a mut [$S; $n]> for &'a mut $PointN<$S> {
#[inline]
fn from(v: &'a mut [$S; $n]) -> &'a mut $PointN<$S> {
unsafe { mem::transmute(v) }
}
}
}
}
fixed_array_conversions!(Point2<S> { x:0, y:1 }, 2);
fixed_array_conversions!(Point3<S> { x:0, y:1, z:2 }, 3);
macro_rules! tuple_conversions {
($PointN:ident <$S:ident> { $($field:ident),+ }, $Tuple:ty) => {
impl<$S> Into<$Tuple> for $PointN<$S> {
#[inline]
fn into(self) -> $Tuple {
match self { $PointN { $($field),+ } => ($($field),+) }
}
}
impl<$S> AsRef<$Tuple> for $PointN<$S> {
#[inline]
fn as_ref(&self) -> &$Tuple {
unsafe { mem::transmute(self) }
}
}
impl<$S> AsMut<$Tuple> for $PointN<$S> {
#[inline]
fn as_mut(&mut self) -> &mut $Tuple {
unsafe { mem::transmute(self) }
}
}
impl<$S> From<$Tuple> for $PointN<$S> {
#[inline]
fn from(v: $Tuple) -> $PointN<$S> {
// We need to use a clone here because we can't pattern match on arrays yet
match v { ($($field),+) => $PointN { $($field: $field),+ } }
}
}
impl<'a, $S> From<&'a $Tuple> for &'a $PointN<$S> {
#[inline]
fn from(v: &'a $Tuple) -> &'a $PointN<$S> {
unsafe { mem::transmute(v) }
}
}
impl<'a, $S> From<&'a mut $Tuple> for &'a mut $PointN<$S> {
#[inline]
fn from(v: &'a mut $Tuple) -> &'a mut $PointN<$S> {
unsafe { mem::transmute(v) }
}
}
}
}
tuple_conversions!(Point2<S> { x, y }, (S, S));
tuple_conversions!(Point3<S> { x, y, z }, (S, S, S));
macro_rules! index_operators {
($PointN:ident<$S:ident>, $n:expr, $Output:ty, $I:ty) => {
impl<$S> Index<$I> for $PointN<$S> {
type Output = $Output;
#[inline]
fn index<'a>(&'a self, i: $I) -> &'a $Output {
let v: &[$S; $n] = self.as_ref(); &v[i]
}
}
impl<$S> IndexMut<$I> for $PointN<$S> {
#[inline]
fn index_mut<'a>(&'a mut self, i: $I) -> &'a mut $Output {
let v: &mut [$S; $n] = self.as_mut(); &mut v[i]
}
}
}
}
index_operators!(Point2<S>, 2, S, usize); impl_tuple_conversions!(Point2<S> { x, y }, (S, S));
index_operators!(Point3<S>, 3, S, usize); impl_tuple_conversions!(Point3<S> { x, y, z }, (S, S, S));
index_operators!(Point2<S>, 2, [S], Range<usize>);
index_operators!(Point3<S>, 3, [S], Range<usize>);
index_operators!(Point2<S>, 2, [S], RangeTo<usize>);
index_operators!(Point3<S>, 3, [S], RangeTo<usize>);
index_operators!(Point2<S>, 2, [S], RangeFrom<usize>);
index_operators!(Point3<S>, 3, [S], RangeFrom<usize>);
index_operators!(Point2<S>, 2, [S], RangeFull);
index_operators!(Point3<S>, 3, [S], RangeFull);
impl<S: BaseNum> fmt::Debug for Point2<S> { impl<S: BaseNum> fmt::Debug for Point2<S> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {

View file

@ -123,75 +123,19 @@ impl<'a, S: BaseFloat> Neg for &'a Quaternion<S> {
fn neg(self) -> Quaternion<S> { Quaternion::from_sv(-self.s, -self.v) } fn neg(self) -> Quaternion<S> { Quaternion::from_sv(-self.s, -self.v) }
} }
/// Generates a binary operator implementation for the permutations of by-ref and by-val impl_binary_operator!(<S: BaseFloat> Mul<S> for Quaternion<S> {
macro_rules! impl_binary_operator {
// When the right operand is a scalar
(<$S:ident> $Binop:ident<$Rhs:ident> for $Lhs:ty { fn $binop:ident($lhs:ident, $rhs:ident) -> $Output:ty { $body:expr } }) => {
impl<$S: BaseFloat> $Binop<$Rhs> for $Lhs {
type Output = $Output;
#[inline]
fn $binop(self, other: $Rhs) -> $Output {
let ($lhs, $rhs) = (self, other); $body
}
}
impl<'a, $S: BaseFloat> $Binop<$Rhs> for &'a $Lhs {
type Output = $Output;
#[inline]
fn $binop(self, other: $Rhs) -> $Output {
let ($lhs, $rhs) = (self, other); $body
}
}
};
// When the right operand is a compound type
(<$S:ident> $Binop:ident<$Rhs:ty> for $Lhs:ty { fn $binop:ident($lhs:ident, $rhs:ident) -> $Output:ty { $body:expr } }) => {
impl<$S: BaseFloat> $Binop<$Rhs> for $Lhs {
type Output = $Output;
#[inline]
fn $binop(self, other: $Rhs) -> $Output {
let ($lhs, $rhs) = (self, other); $body
}
}
impl<'a, $S: BaseFloat> $Binop<&'a $Rhs> for $Lhs {
type Output = $Output;
#[inline]
fn $binop(self, other: &'a $Rhs) -> $Output {
let ($lhs, $rhs) = (self, other); $body
}
}
impl<'a, $S: BaseFloat> $Binop<$Rhs> for &'a $Lhs {
type Output = $Output;
#[inline]
fn $binop(self, other: $Rhs) -> $Output {
let ($lhs, $rhs) = (self, other); $body
}
}
impl<'a, 'b, $S: BaseFloat> $Binop<&'a $Rhs> for &'b $Lhs {
type Output = $Output;
#[inline]
fn $binop(self, other: &'a $Rhs) -> $Output {
let ($lhs, $rhs) = (self, other); $body
}
}
};
}
impl_binary_operator!(<S> Mul<S> for Quaternion<S> {
fn mul(lhs, rhs) -> Quaternion<S> { fn mul(lhs, rhs) -> Quaternion<S> {
Quaternion::from_sv(lhs.s * rhs, lhs.v * rhs) Quaternion::from_sv(lhs.s * rhs, lhs.v * rhs)
} }
}); });
impl_binary_operator!(<S> Div<S> for Quaternion<S> { impl_binary_operator!(<S: BaseFloat> Div<S> for Quaternion<S> {
fn div(lhs, rhs) -> Quaternion<S> { fn div(lhs, rhs) -> Quaternion<S> {
Quaternion::from_sv(lhs.s / rhs, lhs.v / rhs) Quaternion::from_sv(lhs.s / rhs, lhs.v / rhs)
} }
}); });
impl_binary_operator!(<S> Mul<Vector3<S> > for Quaternion<S> { impl_binary_operator!(<S: BaseFloat> Mul<Vector3<S> > for Quaternion<S> {
fn mul(lhs, rhs) -> Vector3<S> {{ fn mul(lhs, rhs) -> Vector3<S> {{
let rhs = rhs.clone(); let rhs = rhs.clone();
let two: S = cast(2i8).unwrap(); let two: S = cast(2i8).unwrap();
@ -200,19 +144,19 @@ impl_binary_operator!(<S> Mul<Vector3<S> > for Quaternion<S> {
}} }}
}); });
impl_binary_operator!(<S> Add<Quaternion<S> > for Quaternion<S> { impl_binary_operator!(<S: BaseFloat> Add<Quaternion<S> > for Quaternion<S> {
fn add(lhs, rhs) -> Quaternion<S> { fn add(lhs, rhs) -> Quaternion<S> {
Quaternion::from_sv(lhs.s + rhs.s, lhs.v + rhs.v) Quaternion::from_sv(lhs.s + rhs.s, lhs.v + rhs.v)
} }
}); });
impl_binary_operator!(<S> Sub<Quaternion<S> > for Quaternion<S> { impl_binary_operator!(<S: BaseFloat> Sub<Quaternion<S> > for Quaternion<S> {
fn sub(lhs, rhs) -> Quaternion<S> { fn sub(lhs, rhs) -> Quaternion<S> {
Quaternion::from_sv(lhs.s - rhs.s, lhs.v - rhs.v) Quaternion::from_sv(lhs.s - rhs.s, lhs.v - rhs.v)
} }
}); });
impl_binary_operator!(<S> Mul<Quaternion<S> > for Quaternion<S> { impl_binary_operator!(<S: BaseFloat> Mul<Quaternion<S> > for Quaternion<S> {
fn mul(lhs, rhs) -> Quaternion<S> { fn mul(lhs, rhs) -> Quaternion<S> {
Quaternion::new(lhs.s * rhs.s - lhs.v.x * rhs.v.x - lhs.v.y * rhs.v.y - lhs.v.z * rhs.v.z, 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.x + lhs.v.x * rhs.s + lhs.v.y * rhs.v.z - lhs.v.z * rhs.v.y,

View file

@ -204,7 +204,7 @@ pub trait Vector: Copy + Clone where
#[inline] pub fn dot<V: Vector>(a: V, b: V) -> V::Scalar { a.dot(b) } #[inline] pub fn dot<V: Vector>(a: V, b: V) -> V::Scalar { a.dot(b) }
// Utility macro for generating associated functions for the vectors // Utility macro for generating associated functions for the vectors
macro_rules! vec { macro_rules! impl_vector {
($VectorN:ident <$S:ident> { $($field:ident),+ }, $n:expr, $constructor:ident) => { ($VectorN:ident <$S:ident> { $($field:ident),+ }, $n:expr, $constructor:ident) => {
#[derive(PartialEq, Eq, Copy, Clone, Hash, RustcEncodable, RustcDecodable)] #[derive(PartialEq, Eq, Copy, Clone, Hash, RustcEncodable, RustcDecodable)]
pub struct $VectorN<S> { $(pub $field: S),+ } pub struct $VectorN<S> { $(pub $field: S),+ }
@ -242,10 +242,10 @@ macro_rules! vec {
impl<S: Copy> Array for $VectorN<S> { impl<S: Copy> Array for $VectorN<S> {
type Element = S; type Element = S;
#[inline] fn sum(self) -> S where S: Add<Output = S> { fold!(add, { $(self.$field),+ }) } #[inline] fn sum(self) -> S where S: Add<Output = S> { fold_array!(add, { $(self.$field),+ }) }
#[inline] fn product(self) -> S where S: Mul<Output = S> { fold!(mul, { $(self.$field),+ }) } #[inline] fn product(self) -> S where S: Mul<Output = S> { fold_array!(mul, { $(self.$field),+ }) }
#[inline] fn min(self) -> S where S: PartialOrd { fold!(partial_min, { $(self.$field),+ }) } #[inline] fn min(self) -> S where S: PartialOrd { fold_array!(partial_min, { $(self.$field),+ }) }
#[inline] fn max(self) -> S where S: PartialOrd { fold!(partial_max, { $(self.$field),+ }) } #[inline] fn max(self) -> S where S: PartialOrd { fold_array!(partial_max, { $(self.$field),+ }) }
} }
impl<S: BaseNum> Vector for $VectorN<S> { impl<S: BaseNum> Vector for $VectorN<S> {
@ -302,233 +302,61 @@ macro_rules! vec {
$VectorN { $($field: rng.gen()),+ } $VectorN { $($field: rng.gen()),+ }
} }
} }
impl_binary_operator!(<S: BaseNum> Add<S> for $VectorN<S> {
fn add(vector, scalar) -> $VectorN<S> { $VectorN::new($(vector.$field + scalar),+) }
});
impl_binary_operator!(<S: BaseNum> Add<$VectorN<S> > for $VectorN<S> {
fn add(lhs, rhs) -> $VectorN<S> { $VectorN::new($(lhs.$field + rhs.$field),+) }
});
impl_binary_operator!(<S: BaseNum> Sub<S> for $VectorN<S> {
fn sub(vector, scalar) -> $VectorN<S> { $VectorN::new($(vector.$field - scalar),+) }
});
impl_binary_operator!(<S: BaseNum> Sub<$VectorN<S> > for $VectorN<S> {
fn sub(lhs, rhs) -> $VectorN<S> { $VectorN::new($(lhs.$field - rhs.$field),+) }
});
impl_binary_operator!(<S: BaseNum> Mul<S> for $VectorN<S> {
fn mul(vector, scalar) -> $VectorN<S> { $VectorN::new($(vector.$field * scalar),+) }
});
impl_binary_operator!(<S: BaseNum> Mul<$VectorN<S> > for $VectorN<S> {
fn mul(lhs, rhs) -> $VectorN<S> { $VectorN::new($(lhs.$field * rhs.$field),+) }
});
impl_binary_operator!(<S: BaseNum> Div<S> for $VectorN<S> {
fn div(vector, scalar) -> $VectorN<S> { $VectorN::new($(vector.$field / scalar),+) }
});
impl_binary_operator!(<S: BaseNum> Div<$VectorN<S> > for $VectorN<S> {
fn div(lhs, rhs) -> $VectorN<S> { $VectorN::new($(lhs.$field / rhs.$field),+) }
});
impl_binary_operator!(<S: BaseNum> Rem<S> for $VectorN<S> {
fn rem(vector, scalar) -> $VectorN<S> { $VectorN::new($(vector.$field % scalar),+) }
});
impl_binary_operator!(<S: BaseNum> Rem<$VectorN<S> > for $VectorN<S> {
fn rem(lhs, rhs) -> $VectorN<S> { $VectorN::new($(lhs.$field % rhs.$field),+) }
});
impl_index_operators!($VectorN<S>, $n, S, usize);
impl_index_operators!($VectorN<S>, $n, [S], Range<usize>);
impl_index_operators!($VectorN<S>, $n, [S], RangeTo<usize>);
impl_index_operators!($VectorN<S>, $n, [S], RangeFrom<usize>);
impl_index_operators!($VectorN<S>, $n, [S], RangeFull);
} }
} }
macro_rules! impl_binary_operator { impl_vector!(Vector2<S> { x, y }, 2, vec2);
($Binop:ident :: $binop:ident, $VectorN:ident { $($field:ident),+ }) => { impl_vector!(Vector3<S> { x, y, z }, 3, vec3);
impl<S: BaseNum> $Binop<S> for $VectorN<S> { impl_vector!(Vector4<S> { x, y, z, w }, 4, vec4);
type Output = $VectorN<S>;
#[inline] impl_fixed_array_conversions!(Vector2<S> { x: 0, y: 1 }, 2);
fn $binop(self, scalar: S) -> $VectorN<S> { impl_fixed_array_conversions!(Vector3<S> { x: 0, y: 1, z: 2 }, 3);
$VectorN::new($(self.$field.$binop(scalar)),+) impl_fixed_array_conversions!(Vector4<S> { x: 0, y: 1, z: 2, w: 3 }, 4);
}
}
impl<'a, S: BaseNum> $Binop<S> for &'a $VectorN<S> { impl_tuple_conversions!(Vector2<S> { x, y }, (S, S));
type Output = $VectorN<S>; impl_tuple_conversions!(Vector3<S> { x, y, z }, (S, S, S));
impl_tuple_conversions!(Vector4<S> { x, y, z, w }, (S, S, S, S));
#[inline]
fn $binop(self, scalar: S) -> $VectorN<S> {
$VectorN::new($(self.$field.$binop(scalar)),+)
}
}
impl<S: BaseNum> $Binop<$VectorN<S>> for $VectorN<S> {
type Output = $VectorN<S>;
#[inline]
fn $binop(self, other: $VectorN<S>) -> $VectorN<S> {
$VectorN::new($(self.$field.$binop(other.$field)),+)
}
}
impl<'a, S: BaseNum> $Binop<&'a $VectorN<S>> for $VectorN<S> {
type Output = $VectorN<S>;
#[inline]
fn $binop(self, other: &'a $VectorN<S>) -> $VectorN<S> {
$VectorN::new($(self.$field.$binop(other.$field)),+)
}
}
impl<'a, S: BaseNum> $Binop<$VectorN<S>> for &'a $VectorN<S> {
type Output = $VectorN<S>;
#[inline]
fn $binop(self, other: $VectorN<S>) -> $VectorN<S> {
$VectorN::new($(self.$field.$binop(other.$field)),+)
}
}
impl<'a, 'b, S: BaseNum> $Binop<&'a $VectorN<S>> for &'b $VectorN<S> {
type Output = $VectorN<S>;
#[inline]
fn $binop(self, other: &'a $VectorN<S>) -> $VectorN<S> {
$VectorN::new($(self.$field.$binop(other.$field)),+)
}
}
}
}
impl_binary_operator!(Add::add, Vector2 { x, y });
impl_binary_operator!(Add::add, Vector3 { x, y, z });
impl_binary_operator!(Add::add, Vector4 { x, y, z, w });
impl_binary_operator!(Sub::sub, Vector2 { x, y });
impl_binary_operator!(Sub::sub, Vector3 { x, y, z });
impl_binary_operator!(Sub::sub, Vector4 { x, y, z, w });
impl_binary_operator!(Mul::mul, Vector2 { x, y });
impl_binary_operator!(Mul::mul, Vector3 { x, y, z });
impl_binary_operator!(Mul::mul, Vector4 { x, y, z, w });
impl_binary_operator!(Div::div, Vector2 { x, y });
impl_binary_operator!(Div::div, Vector3 { x, y, z });
impl_binary_operator!(Div::div, Vector4 { x, y, z, w });
impl_binary_operator!(Rem::rem, Vector2 { x, y });
impl_binary_operator!(Rem::rem, Vector3 { x, y, z });
impl_binary_operator!(Rem::rem, Vector4 { x, y, z, w });
macro_rules! fold {
(&$method:ident, { $x:expr, $y:expr }) => { $x.$method(&$y) };
(&$method:ident, { $x:expr, $y:expr, $z:expr }) => { $x.$method(&$y).$method(&$z) };
(&$method:ident, { $x:expr, $y:expr, $z:expr, $w:expr }) => { $x.$method(&$y).$method(&$z).$method(&$w) };
($method:ident, { $x:expr, $y:expr }) => { $x.$method($y) };
($method:ident, { $x:expr, $y:expr, $z:expr }) => { $x.$method($y).$method($z) };
($method:ident, { $x:expr, $y:expr, $z:expr, $w:expr }) => { $x.$method($y).$method($z).$method($w) };
}
vec!(Vector2<S> { x, y }, 2, vec2);
vec!(Vector3<S> { x, y, z }, 3, vec3);
vec!(Vector4<S> { x, y, z, w }, 4, vec4);
macro_rules! fixed_array_conversions {
($VectorN:ident <$S:ident> { $($field:ident : $index:expr),+ }, $n:expr) => {
impl<$S> Into<[$S; $n]> for $VectorN<$S> {
#[inline]
fn into(self) -> [$S; $n] {
match self { $VectorN { $($field),+ } => [$($field),+] }
}
}
impl<$S> AsRef<[$S; $n]> for $VectorN<$S> {
#[inline]
fn as_ref(&self) -> &[$S; $n] {
unsafe { mem::transmute(self) }
}
}
impl<$S> AsMut<[$S; $n]> for $VectorN<$S> {
#[inline]
fn as_mut(&mut self) -> &mut [$S; $n] {
unsafe { mem::transmute(self) }
}
}
impl<$S: Clone> From<[$S; $n]> for $VectorN<$S> {
#[inline]
fn from(v: [$S; $n]) -> $VectorN<$S> {
// We need to use a clone here because we can't pattern match on arrays yet
$VectorN { $($field: v[$index].clone()),+ }
}
}
impl<'a, $S> From<&'a [$S; $n]> for &'a $VectorN<$S> {
#[inline]
fn from(v: &'a [$S; $n]) -> &'a $VectorN<$S> {
unsafe { mem::transmute(v) }
}
}
impl<'a, $S> From<&'a mut [$S; $n]> for &'a mut $VectorN<$S> {
#[inline]
fn from(v: &'a mut [$S; $n]) -> &'a mut $VectorN<$S> {
unsafe { mem::transmute(v) }
}
}
}
}
fixed_array_conversions!(Vector2<S> { x:0, y:1 }, 2);
fixed_array_conversions!(Vector3<S> { x:0, y:1, z:2 }, 3);
fixed_array_conversions!(Vector4<S> { x:0, y:1, z:2, w:3 }, 4);
macro_rules! tuple_conversions {
($VectorN:ident <$S:ident> { $($field:ident),+ }, $Tuple:ty) => {
impl<$S> Into<$Tuple> for $VectorN<$S> {
#[inline]
fn into(self) -> $Tuple {
match self { $VectorN { $($field),+ } => ($($field),+) }
}
}
impl<$S> AsRef<$Tuple> for $VectorN<$S> {
#[inline]
fn as_ref(&self) -> &$Tuple {
unsafe { mem::transmute(self) }
}
}
impl<$S> AsMut<$Tuple> for $VectorN<$S> {
#[inline]
fn as_mut(&mut self) -> &mut $Tuple {
unsafe { mem::transmute(self) }
}
}
impl<$S> From<$Tuple> for $VectorN<$S> {
#[inline]
fn from(v: $Tuple) -> $VectorN<$S> {
match v { ($($field),+) => $VectorN { $($field: $field),+ } }
}
}
impl<'a, $S> From<&'a $Tuple> for &'a $VectorN<$S> {
#[inline]
fn from(v: &'a $Tuple) -> &'a $VectorN<$S> {
unsafe { mem::transmute(v) }
}
}
impl<'a, $S> From<&'a mut $Tuple> for &'a mut $VectorN<$S> {
#[inline]
fn from(v: &'a mut $Tuple) -> &'a mut $VectorN<$S> {
unsafe { mem::transmute(v) }
}
}
}
}
tuple_conversions!(Vector2<S> { x, y }, (S, S));
tuple_conversions!(Vector3<S> { x, y, z }, (S, S, S));
tuple_conversions!(Vector4<S> { x, y, z, w }, (S, S, S, S));
macro_rules! index_operators {
($VectorN:ident<$S:ident>, $n:expr, $Output:ty, $I:ty) => {
impl<$S> Index<$I> for $VectorN<$S> {
type Output = $Output;
#[inline]
fn index<'a>(&'a self, i: $I) -> &'a $Output {
let v: &[$S; $n] = self.as_ref(); &v[i]
}
}
impl<$S> IndexMut<$I> for $VectorN<$S> {
#[inline]
fn index_mut<'a>(&'a mut self, i: $I) -> &'a mut $Output {
let v: &mut [$S; $n] = self.as_mut(); &mut v[i]
}
}
}
}
index_operators!(Vector2<S>, 2, S, usize);
index_operators!(Vector3<S>, 3, S, usize);
index_operators!(Vector4<S>, 4, S, usize);
index_operators!(Vector2<S>, 2, [S], Range<usize>);
index_operators!(Vector3<S>, 3, [S], Range<usize>);
index_operators!(Vector4<S>, 4, [S], Range<usize>);
index_operators!(Vector2<S>, 2, [S], RangeTo<usize>);
index_operators!(Vector3<S>, 3, [S], RangeTo<usize>);
index_operators!(Vector4<S>, 4, [S], RangeTo<usize>);
index_operators!(Vector2<S>, 2, [S], RangeFrom<usize>);
index_operators!(Vector3<S>, 3, [S], RangeFrom<usize>);
index_operators!(Vector4<S>, 4, [S], RangeFrom<usize>);
index_operators!(Vector2<S>, 2, [S], RangeFull);
index_operators!(Vector3<S>, 3, [S], RangeFull);
index_operators!(Vector4<S>, 4, [S], RangeFull);
/// Operations specific to numeric two-dimensional vectors. /// Operations specific to numeric two-dimensional vectors.
impl<S: BaseNum> Vector2<S> { impl<S: BaseNum> Vector2<S> {