From 0ce28fbe10c3c0d342fdc015c5a7420f08c94176 Mon Sep 17 00:00:00 2001 From: Brendan Zabarauskas Date: Mon, 21 Sep 2015 01:32:53 +1000 Subject: [PATCH 1/3] Remove FixedArray trait in favour of std::convert Fixes #225 --- src/array.rs | 11 -- src/matrix.rs | 306 ++++++++++++++++++---------------------------- src/point.rs | 222 ++++++++++++++++++--------------- src/quaternion.rs | 123 ++++++++++++++++--- src/vector.rs | 185 ++++++++++++++++++++-------- 5 files changed, 480 insertions(+), 367 deletions(-) diff --git a/src/array.rs b/src/array.rs index f5ce491..fe5cb8b 100644 --- a/src/array.rs +++ b/src/array.rs @@ -90,14 +90,3 @@ pub trait Array2+'static, Row: Array1, Element: fn map(&mut self, op: F) -> Self where F: FnMut(&Column) -> Column; } - -/// Homogeneous arrays of elements that can be converted to and from `[T, ..N]` -/// arrays. -pub trait FixedArray { - fn into_fixed(self) -> V; - fn as_fixed<'a>(&'a self) -> &'a V; - fn as_mut_fixed<'a>(&'a mut self) -> &'a mut V; - fn from_fixed(v: V) -> Self; - fn from_fixed_ref<'a>(v: &'a V) -> &'a Self; - fn from_fixed_mut<'a>(v: &'a mut V) -> &'a mut Self; -} diff --git a/src/matrix.rs b/src/matrix.rs index d38df2c..b1a4dba 100644 --- a/src/matrix.rs +++ b/src/matrix.rs @@ -26,7 +26,7 @@ use rust_num::traits::cast; use angle::{Rad, sin, cos, sin_cos}; use approx::ApproxEq; -use array::{Array1, Array2, FixedArray}; +use array::{Array1, Array2}; use num::{BaseFloat, BaseNum}; use point::{Point, Point3}; use quaternion::Quaternion; @@ -557,65 +557,6 @@ impl One for Matrix4 { #[inline] fn one() -> Matrix4 { Matrix4::identity() } } -impl FixedArray<[[S; 2]; 2]> for Matrix2 { - #[inline] - fn into_fixed(self) -> [[S; 2]; 2] { - match self { - Matrix2 { x, y } => [ - x.into_fixed(), - y.into_fixed(), - ], - } - } - - #[inline] - fn as_fixed<'a>(&'a self) -> &'a [[S; 2]; 2] { - unsafe { mem::transmute(self) } - } - - #[inline] - fn as_mut_fixed<'a>(&'a mut self) -> &'a mut [[S; 2]; 2] { - unsafe { mem::transmute(self) } - } - - #[inline] - fn from_fixed(_v: [[S; 2]; 2]) -> Matrix2 { - // match v { - // [x, y] => Matrix2 { - // x: FixedArray::from_fixed(x), - // y: FixedArray::from_fixed(y), - // }, - // } - panic!("Unimplemented, pending a fix for rust-lang/rust#16418"); - } - - #[inline] - fn from_fixed_ref<'a>(v: &'a [[S; 2]; 2]) -> &'a Matrix2 { - unsafe { mem::transmute(v) } - } - - #[inline] - fn from_fixed_mut<'a>(v: &'a mut [[S; 2]; 2]) -> &'a mut Matrix2 { - unsafe { mem::transmute(v) } - } -} - -impl Index for Matrix2 { - type Output = Vector2; - - #[inline] - fn index<'a>(&'a self, i: usize) -> &'a Vector2 { - FixedArray::from_fixed_ref(&self.as_fixed()[i]) - } -} - -impl IndexMut for Matrix2 { - #[inline] - fn index_mut<'a>(&'a mut self, i: usize) -> &'a mut Vector2 { - FixedArray::from_fixed_mut(&mut self.as_mut_fixed()[i]) - } -} - impl Array2, Vector2, S> for Matrix2 { #[inline] fn row(&self, r: usize) -> Vector2 { @@ -637,67 +578,6 @@ impl Array2, Vector2, S> for Matrix2 { } } -impl FixedArray<[[S; 3]; 3]> for Matrix3 { - #[inline] - fn into_fixed(self) -> [[S; 3]; 3] { - match self { - Matrix3 { x, y, z } => [ - x.into_fixed(), - y.into_fixed(), - z.into_fixed(), - ], - } - } - - #[inline] - fn as_fixed<'a>(&'a self) -> &'a [[S; 3]; 3] { - unsafe { mem::transmute(self) } - } - - #[inline] - fn as_mut_fixed<'a>(&'a mut self) -> &'a mut [[S; 3]; 3] { - unsafe { mem::transmute(self) } - } - - #[inline] - fn from_fixed(_v: [[S; 3]; 3]) -> Matrix3 { - // match v { - // [x, y, z] => Matrix3 { - // x: FixedArray::from_fixed(x), - // y: FixedArray::from_fixed(y), - // z: FixedArray::from_fixed(z), - // }, - // } - panic!("Unimplemented, pending a fix for rust-lang/rust#16418") - } - - #[inline] - fn from_fixed_ref<'a>(v: &'a [[S; 3]; 3]) -> &'a Matrix3 { - unsafe { mem::transmute(v) } - } - - #[inline] - fn from_fixed_mut<'a>(v: &'a mut [[S; 3]; 3]) -> &'a mut Matrix3 { - unsafe { mem::transmute(v) } - } -} - -impl Index for Matrix3 { - type Output = Vector3; - - #[inline] - fn index<'a>(&'a self, i: usize) -> &'a Vector3 { - FixedArray::from_fixed_ref(&self.as_fixed()[i]) - } -} - -impl IndexMut for Matrix3 { - #[inline] - fn index_mut<'a>(&'a mut self, i: usize) -> &'a mut Vector3 { - FixedArray::from_fixed_mut(&mut self.as_mut_fixed()[i]) - } -} - impl Array2, Vector3, S> for Matrix3 { #[inline] fn row(&self, r: usize) -> Vector3 { @@ -722,69 +602,6 @@ impl Array2, Vector3, S> for Matrix3 { } } -impl FixedArray<[[S; 4]; 4]> for Matrix4 { - #[inline] - fn into_fixed(self) -> [[S; 4]; 4] { - match self { - Matrix4 { x, y, z, w } => [ - x.into_fixed(), - y.into_fixed(), - z.into_fixed(), - w.into_fixed(), - ], - } - } - - #[inline] - fn as_fixed<'a>(&'a self) -> &'a [[S; 4]; 4] { - unsafe { mem::transmute(self) } - } - - #[inline] - fn as_mut_fixed<'a>(&'a mut self) -> &'a mut [[S; 4]; 4] { - unsafe { mem::transmute(self) } - } - - #[inline] - fn from_fixed(_v: [[S; 4]; 4]) -> Matrix4 { - // match v { - // [x, y, z, w] => Matrix4 { - // x: FixedArray::from_fixed(x), - // y: FixedArray::from_fixed(y), - // z: FixedArray::from_fixed(z), - // w: FixedArray::from_fixed(w), - // }, - // } - panic!("Unimplemented, pending a fix for rust-lang/rust#16418") - } - - #[inline] - fn from_fixed_ref<'a>(v: &'a [[S; 4]; 4]) -> &'a Matrix4 { - unsafe { mem::transmute(v) } - } - - #[inline] - fn from_fixed_mut<'a>(v: &'a mut [[S; 4]; 4]) -> &'a mut Matrix4 { - unsafe { mem::transmute(v) } - } -} - -impl Index for Matrix4 { - type Output = Vector4; - - #[inline] - fn index<'a>(&'a self, i: usize) -> &'a Vector4 { - FixedArray::from_fixed_ref(&self.as_fixed()[i]) - } -} - -impl IndexMut for Matrix4 { - #[inline] - fn index_mut<'a>(&'a mut self, i: usize) -> &'a mut Vector4 { - FixedArray::from_fixed_mut(&mut self.as_mut_fixed()[i]) - } -} - impl Array2, Vector4, S> for Matrix4 { #[inline] fn row(&self, r: usize) -> Vector4 { @@ -1324,7 +1141,126 @@ impl ApproxEq for Matrix4 { } } -// Conversion traits +macro_rules! index_operators { + ($MatrixN:ident <$S:ident>, $VectorN: ident, $n:expr) => { + impl<$S> Index for $MatrixN<$S> { + type Output = $VectorN<$S>; + + #[inline] + fn index<'a>(&'a self, i: usize) -> &'a $VectorN<$S> { + let v: &[[$S; $n]; $n] = self.as_ref(); + From::from(&v[i]) + } + } + + impl<$S> IndexMut for $MatrixN<$S> { + #[inline] + fn index_mut<'a>(&'a mut self, i: usize) -> &'a mut $VectorN<$S> { + let v: &mut [[$S; $n]; $n] = self.as_mut(); + From::from(&mut v[i]) + } + } + }; +} + +index_operators!(Matrix2, Vector2, 2); +index_operators!(Matrix3, Vector3, 3); +index_operators!(Matrix4, Vector4, 4); + +macro_rules! fixed_array_conversions { + ($MatrixN:ident <$S:ident> { $($field:ident : $index:expr),+ }, $n:expr) => { + impl<$S> Into<[[$S; $n]; $n]> for $MatrixN<$S> { + #[inline] + fn into(self) -> [[$S; $n]; $n] { + match self { $MatrixN { $($field),+ } => [$($field.into()),+] } + } + } + + impl<$S> AsRef<[[$S; $n]; $n]> for $MatrixN<$S> { + #[inline] + fn as_ref(&self) -> &[[$S; $n]; $n] { + unsafe { mem::transmute(self) } + } + } + + impl<$S> AsMut<[[$S; $n]; $n]> for $MatrixN<$S> { + #[inline] + fn as_mut(&mut self) -> &mut [[$S; $n]; $n] { + unsafe { mem::transmute(self) } + } + } + + impl<$S: Copy> From<[[$S; $n]; $n]> for $MatrixN<$S> { + #[inline] + fn from(m: [[$S; $n]; $n]) -> $MatrixN<$S> { + // We need to use a copy here because we can't pattern match on arrays yet + $MatrixN { $($field: From::from(m[$index])),+ } + } + } + + impl<'a, $S> From<&'a [[$S; $n]; $n]> for &'a $MatrixN<$S> { + #[inline] + fn from(m: &'a [[$S; $n]; $n]) -> &'a $MatrixN<$S> { + unsafe { mem::transmute(m) } + } + } + + impl<'a, $S> From<&'a mut [[$S; $n]; $n]> for &'a mut $MatrixN<$S> { + #[inline] + fn from(m: &'a mut [[$S; $n]; $n]) -> &'a mut $MatrixN<$S> { + unsafe { mem::transmute(m) } + } + } + + // impl<$S> Into<[$S; ($n * $n)]> for $MatrixN<$S> { + // #[inline] + // fn into(self) -> [[$S; $n]; $n] { + // // TODO: Not sure how to implement this... + // unimplemented!() + // } + // } + + impl<$S> AsRef<[$S; ($n * $n)]> for $MatrixN<$S> { + #[inline] + fn as_ref(&self) -> &[$S; ($n * $n)] { + unsafe { mem::transmute(self) } + } + } + + impl<$S> AsMut<[$S; ($n * $n)]> for $MatrixN<$S> { + #[inline] + fn as_mut(&mut self) -> &mut [$S; ($n * $n)] { + unsafe { mem::transmute(self) } + } + } + + // impl<$S> From<[$S; ($n * $n)]> for $MatrixN<$S> { + // #[inline] + // fn from(m: [$S; ($n * $n)]) -> $MatrixN<$S> { + // // TODO: Not sure how to implement this... + // unimplemented!() + // } + // } + + impl<'a, $S> From<&'a [$S; ($n * $n)]> for &'a $MatrixN<$S> { + #[inline] + fn from(m: &'a [$S; ($n * $n)]) -> &'a $MatrixN<$S> { + unsafe { mem::transmute(m) } + } + } + + impl<'a, $S> From<&'a mut [$S; ($n * $n)]> for &'a mut $MatrixN<$S> { + #[inline] + fn from(m: &'a mut [$S; ($n * $n)]) -> &'a mut $MatrixN<$S> { + unsafe { mem::transmute(m) } + } + } + } +} + +fixed_array_conversions!(Matrix2 { x:0, y:1 }, 2); +fixed_array_conversions!(Matrix3 { x:0, y:1, z:2 }, 3); +fixed_array_conversions!(Matrix4 { x:0, y:1, z:2, w:3 }, 4); impl From> for Matrix3 { /// Clone the elements of a 2-dimensional matrix into the top-left corner diff --git a/src/point.rs b/src/point.rs index a19c15e..dd09f76 100644 --- a/src/point.rs +++ b/src/point.rs @@ -24,7 +24,7 @@ use std::ops::*; use rust_num::{one, zero}; use approx::ApproxEq; -use array::{Array1, FixedArray}; +use array::Array1; use bound::*; use matrix::{Matrix, Matrix4}; use num::{BaseNum, BaseFloat}; @@ -113,54 +113,6 @@ pub trait Point>: Array1 + Clone { fn max(&self, p: &Self) -> Self; } -impl FixedArray<[S; 2]> for Point2 { - #[inline] - fn into_fixed(self) -> [S; 2] { - match self { Point2 { x, y } => [x, y] } - } - - #[inline] - fn as_fixed<'a>(&'a self) -> &'a [S; 2] { - unsafe { mem::transmute(self) } - } - - #[inline] - fn as_mut_fixed<'a>(&'a mut self) -> &'a mut [S; 2] { - unsafe { mem::transmute(self) } - } - - #[inline] - fn from_fixed(_v: [S; 2]) -> Point2 { - // match v { [x, y] => Point2 { x: x, y: y } } - panic!("Unimplemented, pending a fix for rust-lang/rust#16418"); - } - - #[inline] - fn from_fixed_ref<'a>(v: &'a [S; 2]) -> &'a Point2 { - unsafe { mem::transmute(v) } - } - - #[inline] - fn from_fixed_mut<'a>(v: &'a mut [S; 2]) -> &'a mut Point2 { - unsafe { mem::transmute(v) } - } -} - -impl Index for Point2 { - type Output = S; - #[inline] - fn index<'a>(&'a self, i: usize) -> &'a S { - &self.as_fixed()[i] - } -} - -impl IndexMut for Point2 { - #[inline] - fn index_mut<'a>(&'a mut self, i: usize) -> &'a mut S { - &mut self.as_mut_fixed()[i] - } -} - impl Array1 for Point2 { #[inline] fn map(&mut self, mut op: F) -> Point2 where F: FnMut(S) -> S { @@ -268,55 +220,6 @@ impl ApproxEq for Point2 { } } -impl FixedArray<[S; 3]> for Point3 { - #[inline] - fn into_fixed(self) -> [S; 3] { - match self { Point3 { x, y, z } => [x, y, z] } - } - - #[inline] - fn as_fixed<'a>(&'a self) -> &'a [S; 3] { - unsafe { mem::transmute(self) } - } - - #[inline] - fn as_mut_fixed<'a>(&'a mut self) -> &'a mut [S; 3] { - unsafe { mem::transmute(self) } - } - - #[inline] - fn from_fixed(_v: [S; 3]) -> Point3 { - // match v { [x, y, z] => Point3 { x: x, y: y, z: z } } - panic!("Unimplemented, pending a fix for rust-lang/rust#16418") - } - - #[inline] - fn from_fixed_ref<'a>(v: &'a [S; 3]) -> &'a Point3 { - unsafe { mem::transmute(v) } - } - - #[inline] - fn from_fixed_mut<'a>(v: &'a mut [S; 3]) -> &'a mut Point3 { - unsafe { mem::transmute(v) } - } -} - -impl Index for Point3 { - type Output = S; - - #[inline] - fn index<'a>(&'a self, i: usize) -> &'a S { - &self.as_fixed()[i] - } -} - -impl IndexMut for Point3 { - #[inline] - fn index_mut<'a>(&'a mut self, i: usize) -> &'a mut S { - &mut self.as_mut_fixed()[i] - } -} - impl Array1 for Point3 { #[inline] fn map(&mut self, mut op: F) -> Point3 where F: FnMut(S) -> S { @@ -439,6 +342,129 @@ impl ApproxEq for Point3 { } } +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 { x:0, y:1 }, 2); +fixed_array_conversions!(Point3 { 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 { x, y }, (S, S)); +tuple_conversions!(Point3 { x, y, z }, (S, S, S)); + +macro_rules! index_operators { + ($PointN:ident <$S:ident>, $n:expr) => { + impl<$S> Index for $PointN<$S> { + type Output = $S; + + #[inline] + fn index<'a>(&'a self, i: usize) -> &'a $S { + let v: &[$S; $n] = self.as_ref(); &v[i] + } + } + + impl<$S> IndexMut for $PointN<$S> { + #[inline] + fn index_mut<'a>(&'a mut self, i: usize) -> &'a mut $S { + let v: &mut [$S; $n] = self.as_mut(); &mut v[i] + } + } + } +} + +index_operators!(Point2, 2); +index_operators!(Point3, 3); + impl fmt::Debug for Point2 { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "[{:?}, {:?}]", self.x, self.y) diff --git a/src/quaternion.rs b/src/quaternion.rs index 03b3e1a..9f95d71 100644 --- a/src/quaternion.rs +++ b/src/quaternion.rs @@ -35,7 +35,10 @@ use vector::{Vector3, Vector, EuclideanVector}; /// A [quaternion](https://en.wikipedia.org/wiki/Quaternion) in scalar/vector /// form. #[derive(Copy, Clone, PartialEq, RustcEncodable, RustcDecodable)] -pub struct Quaternion { pub s: S, pub v: Vector3 } +pub struct Quaternion { + pub s: S, + pub v: Vector3, +} impl Array1 for Quaternion { #[inline] @@ -48,24 +51,6 @@ impl Array1 for Quaternion { } } -impl Index for Quaternion { - type Output = S; - - #[inline] - fn index<'a>(&'a self, i: usize) -> &'a S { - let slice: &[S; 4] = unsafe { mem::transmute(self) }; - &slice[i] - } -} - -impl IndexMut for Quaternion { - #[inline] - fn index_mut<'a>(&'a mut self, i: usize) -> &'a mut S { - let slice: &'a mut [S; 4] = unsafe { mem::transmute(self) }; - &mut slice[i] - } -} - impl Quaternion { /// Construct a new quaternion from one scalar component and three /// imaginary components @@ -434,6 +419,106 @@ impl Rotation3 for Quaternion where S: 'static { } } +impl Into<[S; 4]> for Quaternion { + #[inline] + fn into(self) -> [S; 4] { + match self.into() { (w, xi, yj, zk) => [w, xi, yj, zk] } + } +} + +impl AsRef<[S; 4]> for Quaternion { + #[inline] + fn as_ref(&self) -> &[S; 4] { + unsafe { mem::transmute(self) } + } +} + +impl AsMut<[S; 4]> for Quaternion { + #[inline] + fn as_mut(&mut self) -> &mut [S; 4] { + unsafe { mem::transmute(self) } + } +} + +impl From<[S; 4]> for Quaternion { + #[inline] + fn from(v: [S; 4]) -> Quaternion { + Quaternion::new(v[0], v[1], v[2], v[3]) + } +} + +impl<'a, S: BaseFloat> From<&'a [S; 4]> for &'a Quaternion { + #[inline] + fn from(v: &'a [S; 4]) -> &'a Quaternion { + unsafe { mem::transmute(v) } + } +} + +impl<'a, S: BaseFloat> From<&'a mut [S; 4]> for &'a mut Quaternion { + #[inline] + fn from(v: &'a mut [S; 4]) -> &'a mut Quaternion { + unsafe { mem::transmute(v) } + } +} + +impl Into<(S, S, S, S)> for Quaternion { + #[inline] + fn into(self) -> (S, S, S, S) { + match self { Quaternion { s, v: Vector3 { x, y, z } } => (s, x, y, z) } + } +} + +impl AsRef<(S, S, S, S)> for Quaternion { + #[inline] + fn as_ref(&self) -> &(S, S, S, S) { + unsafe { mem::transmute(self) } + } +} + +impl AsMut<(S, S, S, S)> for Quaternion { + #[inline] + fn as_mut(&mut self) -> &mut (S, S, S, S) { + unsafe { mem::transmute(self) } + } +} + +impl From<(S, S, S, S)> for Quaternion { + #[inline] + fn from(v: (S, S, S, S)) -> Quaternion { + match v { (w, xi, yj, zk) => Quaternion::new(w, xi, yj, zk) } + } +} + +impl<'a, S: BaseFloat> From<&'a (S, S, S, S)> for &'a Quaternion { + #[inline] + fn from(v: &'a (S, S, S, S)) -> &'a Quaternion { + unsafe { mem::transmute(v) } + } +} + +impl<'a, S: BaseFloat> From<&'a mut (S, S, S, S)> for &'a mut Quaternion { + #[inline] + fn from(v: &'a mut (S, S, S, S)) -> &'a mut Quaternion { + unsafe { mem::transmute(v) } + } +} + +impl Index for Quaternion { + type Output = S; + + #[inline] + fn index<'a>(&'a self, i: usize) -> &'a S { + let v: &[S; 4] = self.as_ref(); &v[i] + } +} + +impl IndexMut for Quaternion { + #[inline] + fn index_mut<'a>(&'a mut self, i: usize) -> &'a mut S { + let v: &mut [S; 4] = self.as_mut(); &mut v[i] + } +} + impl Rand for Quaternion { #[inline] fn rand(rng: &mut R) -> Quaternion { diff --git a/src/vector.rs b/src/vector.rs index f00e90a..8d3708c 100644 --- a/src/vector.rs +++ b/src/vector.rs @@ -106,7 +106,7 @@ use rust_num::{NumCast, Zero, One, zero, one}; use angle::{Rad, atan2, acos}; use approx::ApproxEq; -use array::{Array1, FixedArray}; +use array::Array1; use num::{BaseNum, BaseFloat}; /// A trait that specifies a range of numeric operations for vectors. Not all @@ -188,8 +188,8 @@ pub trait Vector: Array1 + Zero + One { #[inline] pub fn dot>(a: V, b: V) -> S { a.dot(&b) } // Utility macro for generating associated functions for the vectors -macro_rules! vec( - ($Self_:ident <$S:ident> { $($field:ident),+ }, $n:expr, $constructor:ident) => ( +macro_rules! vec { + ($Self_:ident <$S:ident> { $($field:ident),+ }, $n:expr, $constructor:ident) => { #[derive(PartialEq, Eq, Copy, Clone, Hash, RustcEncodable, RustcDecodable)] pub struct $Self_ { $(pub $field: S),+ } @@ -236,55 +236,6 @@ macro_rules! vec( } } - impl<$S> FixedArray<[$S; $n]> for $Self_<$S> { - #[inline] - fn into_fixed(self) -> [$S; $n] { - match self { $Self_ { $($field),+ } => [$($field),+] } - } - - #[inline] - fn as_fixed<'a>(&'a self) -> &'a [$S; $n] { - unsafe { mem::transmute(self) } - } - - #[inline] - fn as_mut_fixed<'a>(&'a mut self) -> &'a mut [$S; $n] { - unsafe { mem::transmute(self) } - } - - #[inline] - fn from_fixed(_v: [$S; $n]) -> $Self_<$S> { - // match v { [$($field),+] => $Self { $($field: $field),+ } } - panic!("Unimplemented, pending a fix for rust-lang/rust#16418"); - } - - #[inline] - fn from_fixed_ref<'a>(v: &'a [$S; $n]) -> &'a $Self_<$S> { - unsafe { mem::transmute(v) } - } - - #[inline] - fn from_fixed_mut<'a>(v: &'a mut [$S; $n]) -> &'a mut $Self_<$S> { - unsafe { mem::transmute(v) } - } - } - - impl<$S: Copy> Index for $Self_<$S> { - type Output = S; - - #[inline] - fn index<'a>(&'a self, i: usize) -> &'a $S { - &self.as_fixed()[i] - } - } - - impl<$S: Copy> IndexMut for $Self_<$S> { - #[inline] - fn index_mut<'a>(&'a mut self, i: usize) -> &'a mut $S { - &mut self.as_mut_fixed()[i] - } - } - impl<$S: Copy> Array1<$S> for $Self_<$S> { #[inline] fn map(&mut self, mut op: F) -> $Self_<$S> where F: FnMut($S) -> $S { @@ -379,8 +330,8 @@ macro_rules! vec( $Self_ { $($field: rng.gen()),+ } } } - ) -); + } +} macro_rules! fold { (&$method:ident, { $x:expr, $y:expr }) => { $x.$method(&$y) }; @@ -395,6 +346,132 @@ vec!(Vector2 { x, y }, 2, vec2); vec!(Vector3 { x, y, z }, 3, vec3); vec!(Vector4 { x, y, z, w }, 4, vec4); +macro_rules! fixed_array_conversions { + ($Self_:ident <$S:ident> { $($field:ident : $index:expr),+ }, $n:expr) => { + + impl<$S> Into<[$S; $n]> for $Self_<$S> { + #[inline] + fn into(self) -> [$S; $n] { + match self { $Self_ { $($field),+ } => [$($field),+] } + } + } + + impl<$S> AsRef<[$S; $n]> for $Self_<$S> { + #[inline] + fn as_ref(&self) -> &[$S; $n] { + unsafe { mem::transmute(self) } + } + } + + impl<$S> AsMut<[$S; $n]> for $Self_<$S> { + #[inline] + fn as_mut(&mut self) -> &mut [$S; $n] { + unsafe { mem::transmute(self) } + } + } + + impl<$S: Clone> From<[$S; $n]> for $Self_<$S> { + #[inline] + fn from(v: [$S; $n]) -> $Self_<$S> { + // We need to use a clone here because we can't pattern match on arrays yet + $Self_ { $($field: v[$index].clone()),+ } + } + } + + impl<'a, $S> From<&'a [$S; $n]> for &'a $Self_<$S> { + #[inline] + fn from(v: &'a [$S; $n]) -> &'a $Self_<$S> { + unsafe { mem::transmute(v) } + } + } + + impl<'a, $S> From<&'a mut [$S; $n]> for &'a mut $Self_<$S> { + #[inline] + fn from(v: &'a mut [$S; $n]) -> &'a mut $Self_<$S> { + unsafe { mem::transmute(v) } + } + } + } +} + +fixed_array_conversions!(Vector2 { x:0, y:1 }, 2); +fixed_array_conversions!(Vector3 { x:0, y:1, z:2 }, 3); +fixed_array_conversions!(Vector4 { x:0, y:1, z:2, w:3 }, 4); + +macro_rules! tuple_conversions { + ($Self_:ident <$S:ident> { $($field:ident),+ }, $Tuple:ty) => { + impl<$S> Into<$Tuple> for $Self_<$S> { + #[inline] + fn into(self) -> $Tuple { + match self { $Self_ { $($field),+ } => ($($field),+) } + } + } + + impl<$S> AsRef<$Tuple> for $Self_<$S> { + #[inline] + fn as_ref(&self) -> &$Tuple { + unsafe { mem::transmute(self) } + } + } + + impl<$S> AsMut<$Tuple> for $Self_<$S> { + #[inline] + fn as_mut(&mut self) -> &mut $Tuple { + unsafe { mem::transmute(self) } + } + } + + impl<$S> From<$Tuple> for $Self_<$S> { + #[inline] + fn from(v: $Tuple) -> $Self_<$S> { + match v { ($($field),+) => $Self_ { $($field: $field),+ } } + } + } + + impl<'a, $S> From<&'a $Tuple> for &'a $Self_<$S> { + #[inline] + fn from(v: &'a $Tuple) -> &'a $Self_<$S> { + unsafe { mem::transmute(v) } + } + } + + impl<'a, $S> From<&'a mut $Tuple> for &'a mut $Self_<$S> { + #[inline] + fn from(v: &'a mut $Tuple) -> &'a mut $Self_<$S> { + unsafe { mem::transmute(v) } + } + } + } +} + +tuple_conversions!(Vector2 { x, y }, (S, S)); +tuple_conversions!(Vector3 { x, y, z }, (S, S, S)); +tuple_conversions!(Vector4 { x, y, z, w }, (S, S, S, S)); + +macro_rules! index_operators { + ($Self_:ident <$S:ident>, $n:expr) => { + impl<$S> Index for $Self_<$S> { + type Output = $S; + + #[inline] + fn index<'a>(&'a self, i: usize) -> &'a $S { + let v: &[$S; $n] = self.as_ref(); &v[i] + } + } + + impl<$S> IndexMut for $Self_<$S> { + #[inline] + fn index_mut<'a>(&'a mut self, i: usize) -> &'a mut $S { + let v: &mut [$S; $n] = self.as_mut(); &mut v[i] + } + } + } +} + +index_operators!(Vector2, 2); +index_operators!(Vector3, 3); +index_operators!(Vector4, 4); + /// Operations specific to numeric two-dimensional vectors. impl Vector2 { /// A unit vector in the `x` direction. From aff340dc1e4860abe802db0b444bf798f7599afc Mon Sep 17 00:00:00 2001 From: Brendan Zabarauskas Date: Mon, 21 Sep 2015 07:56:03 +1000 Subject: [PATCH 2/3] Add range index operators --- src/matrix.rs | 32 ++++++++++++++++++++++---------- src/point.rs | 24 ++++++++++++++++-------- src/quaternion.rs | 32 +++++++++++++++++++++----------- src/vector.rs | 30 +++++++++++++++++++++--------- 4 files changed, 80 insertions(+), 38 deletions(-) diff --git a/src/matrix.rs b/src/matrix.rs index b1a4dba..4a9d07a 100644 --- a/src/matrix.rs +++ b/src/matrix.rs @@ -1142,30 +1142,42 @@ impl ApproxEq for Matrix4 { } macro_rules! index_operators { - ($MatrixN:ident <$S:ident>, $VectorN: ident, $n:expr) => { - impl<$S> Index for $MatrixN<$S> { - type Output = $VectorN<$S>; + ($MatrixN:ident<$S:ident>, $n:expr, $Output:ty, $I:ty) => { + impl<$S> Index<$I> for $MatrixN<$S> { + type Output = $Output; #[inline] - fn index<'a>(&'a self, i: usize) -> &'a $VectorN<$S> { + fn index<'a>(&'a self, i: $I) -> &'a $Output { let v: &[[$S; $n]; $n] = self.as_ref(); From::from(&v[i]) } } - impl<$S> IndexMut for $MatrixN<$S> { + impl<$S> IndexMut<$I> for $MatrixN<$S> { #[inline] - fn index_mut<'a>(&'a mut self, i: usize) -> &'a mut $VectorN<$S> { + fn index_mut<'a>(&'a mut self, i: $I) -> &'a mut $Output { let v: &mut [[$S; $n]; $n] = self.as_mut(); From::from(&mut v[i]) } } - }; + } } -index_operators!(Matrix2, Vector2, 2); -index_operators!(Matrix3, Vector3, 3); -index_operators!(Matrix4, Vector4, 4); +index_operators!(Matrix2, 2, Vector2, usize); +index_operators!(Matrix3, 3, Vector3, usize); +index_operators!(Matrix4, 4, Vector4, usize); +// index_operators!(Matrix2, 2, [Vector2], Range); +// index_operators!(Matrix3, 3, [Vector3], Range); +// index_operators!(Matrix4, 4, [Vector4], Range); +// index_operators!(Matrix2, 2, [Vector2], RangeTo); +// index_operators!(Matrix3, 3, [Vector3], RangeTo); +// index_operators!(Matrix4, 4, [Vector4], RangeTo); +// index_operators!(Matrix2, 2, [Vector2], RangeFrom); +// index_operators!(Matrix3, 3, [Vector3], RangeFrom); +// index_operators!(Matrix4, 4, [Vector4], RangeFrom); +// index_operators!(Matrix2, 2, [Vector2], RangeFull); +// index_operators!(Matrix3, 3, [Vector3], RangeFull); +// index_operators!(Matrix4, 4, [Vector4], RangeFull); macro_rules! fixed_array_conversions { ($MatrixN:ident <$S:ident> { $($field:ident : $index:expr),+ }, $n:expr) => { diff --git a/src/point.rs b/src/point.rs index dd09f76..55b2c5d 100644 --- a/src/point.rs +++ b/src/point.rs @@ -443,27 +443,35 @@ tuple_conversions!(Point2 { x, y }, (S, S)); tuple_conversions!(Point3 { x, y, z }, (S, S, S)); macro_rules! index_operators { - ($PointN:ident <$S:ident>, $n:expr) => { - impl<$S> Index for $PointN<$S> { - type Output = $S; + ($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: usize) -> &'a $S { + fn index<'a>(&'a self, i: $I) -> &'a $Output { let v: &[$S; $n] = self.as_ref(); &v[i] } } - impl<$S> IndexMut for $PointN<$S> { + impl<$S> IndexMut<$I> for $PointN<$S> { #[inline] - fn index_mut<'a>(&'a mut self, i: usize) -> &'a mut $S { + 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, 2); -index_operators!(Point3, 3); +index_operators!(Point2, 2, S, usize); +index_operators!(Point3, 3, S, usize); +index_operators!(Point2, 2, [S], Range); +index_operators!(Point3, 3, [S], Range); +index_operators!(Point2, 2, [S], RangeTo); +index_operators!(Point3, 3, [S], RangeTo); +index_operators!(Point2, 2, [S], RangeFrom); +index_operators!(Point3, 3, [S], RangeFrom); +index_operators!(Point2, 2, [S], RangeFull); +index_operators!(Point3, 3, [S], RangeFull); impl fmt::Debug for Point2 { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { diff --git a/src/quaternion.rs b/src/quaternion.rs index 9f95d71..9db02e6 100644 --- a/src/quaternion.rs +++ b/src/quaternion.rs @@ -503,21 +503,31 @@ impl<'a, S: BaseFloat> From<&'a mut (S, S, S, S)> for &'a mut Quaternion { } } -impl Index for Quaternion { - type Output = S; +macro_rules! index_operators { + ($S:ident, $Output:ty, $I:ty) => { + impl<$S: BaseFloat> Index<$I> for Quaternion<$S> { + type Output = $Output; - #[inline] - fn index<'a>(&'a self, i: usize) -> &'a S { - let v: &[S; 4] = self.as_ref(); &v[i] + #[inline] + fn index<'a>(&'a self, i: $I) -> &'a $Output { + let v: &[$S; 4] = self.as_ref(); &v[i] + } + } + + impl<$S: BaseFloat> IndexMut<$I> for Quaternion<$S> { + #[inline] + fn index_mut<'a>(&'a mut self, i: $I) -> &'a mut $Output { + let v: &mut [$S; 4] = self.as_mut(); &mut v[i] + } + } } } -impl IndexMut for Quaternion { - #[inline] - fn index_mut<'a>(&'a mut self, i: usize) -> &'a mut S { - let v: &mut [S; 4] = self.as_mut(); &mut v[i] - } -} +index_operators!(S, S, usize); +index_operators!(S, [S], Range); +index_operators!(S, [S], RangeTo); +index_operators!(S, [S], RangeFrom); +index_operators!(S, [S], RangeFull); impl Rand for Quaternion { #[inline] diff --git a/src/vector.rs b/src/vector.rs index 8d3708c..8015ab5 100644 --- a/src/vector.rs +++ b/src/vector.rs @@ -449,28 +449,40 @@ tuple_conversions!(Vector3 { x, y, z }, (S, S, S)); tuple_conversions!(Vector4 { x, y, z, w }, (S, S, S, S)); macro_rules! index_operators { - ($Self_:ident <$S:ident>, $n:expr) => { - impl<$S> Index for $Self_<$S> { - type Output = $S; + ($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: usize) -> &'a $S { + fn index<'a>(&'a self, i: $I) -> &'a $Output { let v: &[$S; $n] = self.as_ref(); &v[i] } } - impl<$S> IndexMut for $Self_<$S> { + impl<$S> IndexMut<$I> for $VectorN<$S> { #[inline] - fn index_mut<'a>(&'a mut self, i: usize) -> &'a mut $S { + 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, 2); -index_operators!(Vector3, 3); -index_operators!(Vector4, 4); +index_operators!(Vector2, 2, S, usize); +index_operators!(Vector3, 3, S, usize); +index_operators!(Vector4, 4, S, usize); +index_operators!(Vector2, 2, [S], Range); +index_operators!(Vector3, 3, [S], Range); +index_operators!(Vector4, 4, [S], Range); +index_operators!(Vector2, 2, [S], RangeTo); +index_operators!(Vector3, 3, [S], RangeTo); +index_operators!(Vector4, 4, [S], RangeTo); +index_operators!(Vector2, 2, [S], RangeFrom); +index_operators!(Vector3, 3, [S], RangeFrom); +index_operators!(Vector4, 4, [S], RangeFrom); +index_operators!(Vector2, 2, [S], RangeFull); +index_operators!(Vector3, 3, [S], RangeFull); +index_operators!(Vector4, 4, [S], RangeFull); /// Operations specific to numeric two-dimensional vectors. impl Vector2 { From 69caaf48b662d846cb9a7bde42ab42454690931c Mon Sep 17 00:00:00 2001 From: Brendan Zabarauskas Date: Sun, 27 Sep 2015 13:01:14 +1000 Subject: [PATCH 3/3] Add index tests --- src/point.rs | 82 ++++++++++++++++++++++++ src/vector.rs | 171 +++++++++++++++++++++++++++++++++++++++++++------- 2 files changed, 229 insertions(+), 24 deletions(-) diff --git a/src/point.rs b/src/point.rs index 55b2c5d..3cf50c3 100644 --- a/src/point.rs +++ b/src/point.rs @@ -507,3 +507,85 @@ impl Bound for Point3 { } } } + +#[cfg(test)] +mod tests { + mod point2 { + use point::*; + + const POINT2: Point2 = Point2 { x: 1, y: 2 }; + + #[test] + fn test_index() { + assert_eq!(POINT2[0], POINT2.x); + assert_eq!(POINT2[1], POINT2.y); + } + + #[test] + fn test_index_mut() { + let mut p = POINT2; + *&mut p[0] = 0; + assert_eq!(p, [0, 2].into()); + } + + #[test] + #[should_panic] + fn test_index_out_of_bounds() { + POINT2[2]; + } + + #[test] + fn test_index_range() { + assert_eq!(&POINT2[..0], &[]); + assert_eq!(&POINT2[..1], &[1]); + assert_eq!(POINT2[..0].len(), 0); + assert_eq!(POINT2[..1].len(), 1); + assert_eq!(&POINT2[2..], &[]); + assert_eq!(&POINT2[1..], &[2]); + assert_eq!(POINT2[2..].len(), 0); + assert_eq!(POINT2[1..].len(), 1); + assert_eq!(&POINT2[..], &[1, 2]); + assert_eq!(POINT2[..].len(), 2); + } + } + + mod point3 { + use point::*; + + const POINT3: Point3 = Point3 { x: 1, y: 2, z: 3 }; + + #[test] + fn test_index() { + assert_eq!(POINT3[0], POINT3.x); + assert_eq!(POINT3[1], POINT3.y); + assert_eq!(POINT3[2], POINT3.z); + } + + #[test] + fn test_index_mut() { + let mut p = POINT3; + *&mut p[1] = 0; + assert_eq!(p, [1, 0, 3].into()); + } + + #[test] + #[should_panic] + fn test_index_out_of_bounds() { + POINT3[3]; + } + + #[test] + fn test_index_range() { + assert_eq!(&POINT3[..1], &[1]); + assert_eq!(&POINT3[..2], &[1, 2]); + assert_eq!(POINT3[..1].len(), 1); + assert_eq!(POINT3[..2].len(), 2); + assert_eq!(&POINT3[2..], &[3]); + assert_eq!(&POINT3[1..], &[2, 3]); + assert_eq!(POINT3[2..].len(), 1); + assert_eq!(POINT3[1..].len(), 2); + assert_eq!(&POINT3[..], &[1, 2, 3]); + assert_eq!(POINT3[..].len(), 3); + } + } +} diff --git a/src/vector.rs b/src/vector.rs index 8015ab5..4e42a93 100644 --- a/src/vector.rs +++ b/src/vector.rs @@ -347,47 +347,47 @@ vec!(Vector3 { x, y, z }, 3, vec3); vec!(Vector4 { x, y, z, w }, 4, vec4); macro_rules! fixed_array_conversions { - ($Self_:ident <$S:ident> { $($field:ident : $index:expr),+ }, $n:expr) => { + ($VectorN:ident <$S:ident> { $($field:ident : $index:expr),+ }, $n:expr) => { - impl<$S> Into<[$S; $n]> for $Self_<$S> { + impl<$S> Into<[$S; $n]> for $VectorN<$S> { #[inline] fn into(self) -> [$S; $n] { - match self { $Self_ { $($field),+ } => [$($field),+] } + match self { $VectorN { $($field),+ } => [$($field),+] } } } - impl<$S> AsRef<[$S; $n]> for $Self_<$S> { + 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 $Self_<$S> { + 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 $Self_<$S> { + impl<$S: Clone> From<[$S; $n]> for $VectorN<$S> { #[inline] - fn from(v: [$S; $n]) -> $Self_<$S> { + fn from(v: [$S; $n]) -> $VectorN<$S> { // We need to use a clone here because we can't pattern match on arrays yet - $Self_ { $($field: v[$index].clone()),+ } + $VectorN { $($field: v[$index].clone()),+ } } } - impl<'a, $S> From<&'a [$S; $n]> for &'a $Self_<$S> { + impl<'a, $S> From<&'a [$S; $n]> for &'a $VectorN<$S> { #[inline] - fn from(v: &'a [$S; $n]) -> &'a $Self_<$S> { + fn from(v: &'a [$S; $n]) -> &'a $VectorN<$S> { unsafe { mem::transmute(v) } } } - impl<'a, $S> From<&'a mut [$S; $n]> for &'a mut $Self_<$S> { + impl<'a, $S> From<&'a mut [$S; $n]> for &'a mut $VectorN<$S> { #[inline] - fn from(v: &'a mut [$S; $n]) -> &'a mut $Self_<$S> { + fn from(v: &'a mut [$S; $n]) -> &'a mut $VectorN<$S> { unsafe { mem::transmute(v) } } } @@ -399,45 +399,45 @@ fixed_array_conversions!(Vector3 { x:0, y:1, z:2 }, 3); fixed_array_conversions!(Vector4 { x:0, y:1, z:2, w:3 }, 4); macro_rules! tuple_conversions { - ($Self_:ident <$S:ident> { $($field:ident),+ }, $Tuple:ty) => { - impl<$S> Into<$Tuple> for $Self_<$S> { + ($VectorN:ident <$S:ident> { $($field:ident),+ }, $Tuple:ty) => { + impl<$S> Into<$Tuple> for $VectorN<$S> { #[inline] fn into(self) -> $Tuple { - match self { $Self_ { $($field),+ } => ($($field),+) } + match self { $VectorN { $($field),+ } => ($($field),+) } } } - impl<$S> AsRef<$Tuple> for $Self_<$S> { + impl<$S> AsRef<$Tuple> for $VectorN<$S> { #[inline] fn as_ref(&self) -> &$Tuple { unsafe { mem::transmute(self) } } } - impl<$S> AsMut<$Tuple> for $Self_<$S> { + impl<$S> AsMut<$Tuple> for $VectorN<$S> { #[inline] fn as_mut(&mut self) -> &mut $Tuple { unsafe { mem::transmute(self) } } } - impl<$S> From<$Tuple> for $Self_<$S> { + impl<$S> From<$Tuple> for $VectorN<$S> { #[inline] - fn from(v: $Tuple) -> $Self_<$S> { - match v { ($($field),+) => $Self_ { $($field: $field),+ } } + fn from(v: $Tuple) -> $VectorN<$S> { + match v { ($($field),+) => $VectorN { $($field: $field),+ } } } } - impl<'a, $S> From<&'a $Tuple> for &'a $Self_<$S> { + impl<'a, $S> From<&'a $Tuple> for &'a $VectorN<$S> { #[inline] - fn from(v: &'a $Tuple) -> &'a $Self_<$S> { + fn from(v: &'a $Tuple) -> &'a $VectorN<$S> { unsafe { mem::transmute(v) } } } - impl<'a, $S> From<&'a mut $Tuple> for &'a mut $Self_<$S> { + impl<'a, $S> From<&'a mut $Tuple> for &'a mut $VectorN<$S> { #[inline] - fn from(v: &'a mut $Tuple) -> &'a mut $Self_<$S> { + fn from(v: &'a mut $Tuple) -> &'a mut $VectorN<$S> { unsafe { mem::transmute(v) } } } @@ -685,3 +685,126 @@ impl fmt::Debug for Vector4 { write!(f, "[{:?}, {:?}, {:?}, {:?}]", self.x, self.y, self.z, self.w) } } + +#[cfg(test)] +mod tests { + mod vector2 { + use vector::*; + + const VECTOR2: Vector2 = Vector2 { x: 1, y: 2 }; + + #[test] + fn test_index() { + assert_eq!(VECTOR2[0], VECTOR2.x); + assert_eq!(VECTOR2[1], VECTOR2.y); + } + + #[test] + fn test_index_mut() { + let mut v = VECTOR2; + *&mut v[0] = 0; + assert_eq!(v, [0, 2].into()); + } + + #[test] + #[should_panic] + fn test_index_out_of_bounds() { + VECTOR2[2]; + } + + #[test] + fn test_index_range() { + assert_eq!(&VECTOR2[..0], &[]); + assert_eq!(&VECTOR2[..1], &[1]); + assert_eq!(VECTOR2[..0].len(), 0); + assert_eq!(VECTOR2[..1].len(), 1); + assert_eq!(&VECTOR2[2..], &[]); + assert_eq!(&VECTOR2[1..], &[2]); + assert_eq!(VECTOR2[2..].len(), 0); + assert_eq!(VECTOR2[1..].len(), 1); + assert_eq!(&VECTOR2[..], &[1, 2]); + assert_eq!(VECTOR2[..].len(), 2); + } + } + + mod vector3 { + use vector::*; + + const VECTOR3: Vector3 = Vector3 { x: 1, y: 2, z: 3 }; + + #[test] + fn test_index() { + assert_eq!(VECTOR3[0], VECTOR3.x); + assert_eq!(VECTOR3[1], VECTOR3.y); + assert_eq!(VECTOR3[2], VECTOR3.z); + } + + #[test] + fn test_index_mut() { + let mut v = VECTOR3; + *&mut v[1] = 0; + assert_eq!(v, [1, 0, 3].into()); + } + + #[test] + #[should_panic] + fn test_index_out_of_bounds() { + VECTOR3[3]; + } + + #[test] + fn test_index_range() { + assert_eq!(&VECTOR3[..1], &[1]); + assert_eq!(&VECTOR3[..2], &[1, 2]); + assert_eq!(VECTOR3[..1].len(), 1); + assert_eq!(VECTOR3[..2].len(), 2); + assert_eq!(&VECTOR3[2..], &[3]); + assert_eq!(&VECTOR3[1..], &[2, 3]); + assert_eq!(VECTOR3[2..].len(), 1); + assert_eq!(VECTOR3[1..].len(), 2); + assert_eq!(&VECTOR3[..], &[1, 2, 3]); + assert_eq!(VECTOR3[..].len(), 3); + } + } + + mod vector4 { + use vector::*; + + const VECTOR4: Vector4 = Vector4 { x: 1, y: 2, z: 3, w: 4 }; + + #[test] + fn test_index() { + assert_eq!(VECTOR4[0], VECTOR4.x); + assert_eq!(VECTOR4[1], VECTOR4.y); + assert_eq!(VECTOR4[2], VECTOR4.z); + assert_eq!(VECTOR4[3], VECTOR4.w); + } + + #[test] + fn test_index_mut() { + let mut v = VECTOR4; + *&mut v[2] = 0; + assert_eq!(v, [1, 2, 0, 4].into()); + } + + #[test] + #[should_panic] + fn test_index_out_of_bounds() { + VECTOR4[4]; + } + + #[test] + fn test_index_range() { + assert_eq!(&VECTOR4[..2], &[1, 2]); + assert_eq!(&VECTOR4[..3], &[1, 2, 3]); + assert_eq!(VECTOR4[..2].len(), 2); + assert_eq!(VECTOR4[..3].len(), 3); + assert_eq!(&VECTOR4[2..], &[3, 4]); + assert_eq!(&VECTOR4[1..], &[2, 3, 4]); + assert_eq!(VECTOR4[2..].len(), 2); + assert_eq!(VECTOR4[1..].len(), 3); + assert_eq!(&VECTOR4[..], &[1, 2, 3, 4]); + assert_eq!(VECTOR4[..].len(), 4); + } + } +}