Make epsilon an associated type on ApproxEq

This commit is contained in:
Brendan Zabarauskas 2015-11-03 14:00:39 +11:00
parent 78f86a33cd
commit 0584bcac64
8 changed files with 49 additions and 27 deletions

View file

@ -80,7 +80,7 @@ pub trait Angle
> >
: Clone + Zero : Clone + Zero
+ PartialEq + PartialOrd + PartialEq + PartialOrd
+ ApproxEq<S> + ApproxEq<Epsilon = S>
+ Neg<Output=Self> + Neg<Output=Self>
+ Into<Rad<S>> + Into<Rad<S>>
+ Into<Deg<S>> + Into<Deg<S>>
@ -279,16 +279,18 @@ fmt::Debug for Deg<S> {
} }
} }
impl<S: BaseFloat> impl<S: BaseFloat> ApproxEq for Rad<S> {
ApproxEq<S> for Rad<S> { type Epsilon = S;
#[inline] #[inline]
fn approx_eq_eps(&self, other: &Rad<S>, epsilon: &S) -> bool { fn approx_eq_eps(&self, other: &Rad<S>, epsilon: &S) -> bool {
self.s.approx_eq_eps(&other.s, epsilon) self.s.approx_eq_eps(&other.s, epsilon)
} }
} }
impl<S: BaseFloat> impl<S: BaseFloat> ApproxEq for Deg<S> {
ApproxEq<S> for Deg<S> { type Epsilon = S;
#[inline] #[inline]
fn approx_eq_eps(&self, other: &Deg<S>, epsilon: &S) -> bool { fn approx_eq_eps(&self, other: &Deg<S>, epsilon: &S) -> bool {
self.s.approx_eq_eps(&other.s, epsilon) self.s.approx_eq_eps(&other.s, epsilon)

View file

@ -16,23 +16,26 @@
use rust_num::{Float, NumCast}; use rust_num::{Float, NumCast};
use rust_num::traits::cast; use rust_num::traits::cast;
pub trait ApproxEq<T: NumCast + Float>: Sized { pub trait ApproxEq: Sized {
fn approx_epsilon(_hack: Option<Self>) -> T { type Epsilon: NumCast + Float;
fn approx_epsilon() -> Self::Epsilon {
cast(1.0e-5f64).unwrap() cast(1.0e-5f64).unwrap()
} }
fn approx_eq(&self, other: &Self) -> bool { fn approx_eq(&self, other: &Self) -> bool {
let eps: T = ApproxEq::approx_epsilon(None::<Self>); self.approx_eq_eps(other, &Self::approx_epsilon())
self.approx_eq_eps(other, &eps)
} }
fn approx_eq_eps(&self, other: &Self, epsilon: &T) -> bool; fn approx_eq_eps(&self, other: &Self, epsilon: &Self::Epsilon) -> bool;
} }
macro_rules! approx_float( macro_rules! approx_float(
($S:ident) => ( ($S:ident) => (
impl ApproxEq<$S> for $S { impl ApproxEq for $S {
type Epsilon = $S;
#[inline] #[inline]
fn approx_eq_eps(&self, other: &$S, epsilon: &$S) -> bool { fn approx_eq_eps(&self, other: &$S, epsilon: &$S) -> bool {
(*self - *other).abs() < *epsilon (*self - *other).abs() < *epsilon
@ -62,9 +65,8 @@ macro_rules! assert_approx_eq(
($given: expr, $expected: expr) => ({ ($given: expr, $expected: expr) => ({
let (given_val, expected_val) = (&($given), &($expected)); let (given_val, expected_val) = (&($given), &($expected));
if !given_val.approx_eq(expected_val) { if !given_val.approx_eq(expected_val) {
panic!("assertion failed: `left ≈ right` (left: `{:?}`, right: `{:?}`, tolerance: `{:?}`)", panic!("assertion failed: `left ≈ right` (left: `{:?}`, right: `{:?}`)",
*given_val, *expected_val, *given_val, *expected_val
ApproxEq::approx_epsilon(Some(*given_val))
); );
} }
}) })

View file

@ -249,7 +249,7 @@ impl<S: Copy + Neg<Output = S>> Matrix4<S> {
} }
} }
pub trait Matrix<S: BaseFloat, V: Vector<S> + 'static>: Array2<V, V, S> + ApproxEq<S> + Sized // where pub trait Matrix<S: BaseFloat, V: Vector<S> + 'static>: Array2<V, V, S> + ApproxEq<Epsilon = S> + Sized // where
// FIXME: blocked by rust-lang/rust#20671 // FIXME: blocked by rust-lang/rust#20671
// //
// for<'a, 'b> &'a Self: Add<&'b Self, Output = Self>, // for<'a, 'b> &'a Self: Add<&'b Self, Output = Self>,
@ -790,7 +790,9 @@ impl<S: BaseFloat> Matrix<S, Vector4<S>> for Matrix4<S> {
} }
} }
impl<S: BaseFloat> ApproxEq<S> for Matrix2<S> { impl<S: BaseFloat> ApproxEq for Matrix2<S> {
type Epsilon = S;
#[inline] #[inline]
fn approx_eq_eps(&self, other: &Matrix2<S>, epsilon: &S) -> bool { fn approx_eq_eps(&self, other: &Matrix2<S>, epsilon: &S) -> bool {
self[0].approx_eq_eps(&other[0], epsilon) && self[0].approx_eq_eps(&other[0], epsilon) &&
@ -798,7 +800,9 @@ impl<S: BaseFloat> ApproxEq<S> for Matrix2<S> {
} }
} }
impl<S: BaseFloat> ApproxEq<S> for Matrix3<S> { impl<S: BaseFloat> ApproxEq for Matrix3<S> {
type Epsilon = S;
#[inline] #[inline]
fn approx_eq_eps(&self, other: &Matrix3<S>, epsilon: &S) -> bool { fn approx_eq_eps(&self, other: &Matrix3<S>, epsilon: &S) -> bool {
self[0].approx_eq_eps(&other[0], epsilon) && self[0].approx_eq_eps(&other[0], epsilon) &&
@ -807,7 +811,9 @@ impl<S: BaseFloat> ApproxEq<S> for Matrix3<S> {
} }
} }
impl<S: BaseFloat> ApproxEq<S> for Matrix4<S> { impl<S: BaseFloat> ApproxEq for Matrix4<S> {
type Epsilon = S;
#[inline] #[inline]
fn approx_eq_eps(&self, other: &Matrix4<S>, epsilon: &S) -> bool { fn approx_eq_eps(&self, other: &Matrix4<S>, epsilon: &S) -> bool {
self[0].approx_eq_eps(&other[0], epsilon) && self[0].approx_eq_eps(&other[0], epsilon) &&

View file

@ -110,7 +110,7 @@ impl BaseInt for u64 {}
impl BaseInt for usize {} impl BaseInt for usize {}
/// Base floating point types /// Base floating point types
pub trait BaseFloat : BaseNum + Float + ApproxEq<Self> {} pub trait BaseFloat : BaseNum + Float + ApproxEq<Epsilon = Self> {}
impl BaseFloat for f32 {} impl BaseFloat for f32 {}
impl BaseFloat for f64 {} impl BaseFloat for f64 {}

View file

@ -190,7 +190,9 @@ impl<S: BaseNum> Point<S> for Point2<S> {
} }
} }
impl<S: BaseFloat> ApproxEq<S> for Point2<S> { impl<S: BaseFloat> ApproxEq for Point2<S> {
type Epsilon = S;
#[inline] #[inline]
fn approx_eq_eps(&self, other: &Point2<S>, epsilon: &S) -> bool { fn approx_eq_eps(&self, other: &Point2<S>, epsilon: &S) -> bool {
self.x.approx_eq_eps(&other.x, epsilon) && self.x.approx_eq_eps(&other.x, epsilon) &&
@ -270,7 +272,9 @@ impl<S: BaseNum> Point<S> for Point3<S> {
} }
} }
impl<S: BaseFloat> ApproxEq<S> for Point3<S> { impl<S: BaseFloat> ApproxEq for Point3<S> {
type Epsilon = S;
#[inline] #[inline]
fn approx_eq_eps(&self, other: &Point3<S>, epsilon: &S) -> bool { fn approx_eq_eps(&self, other: &Point3<S>, epsilon: &S) -> bool {
self.x.approx_eq_eps(&other.x, epsilon) && self.x.approx_eq_eps(&other.x, epsilon) &&

View file

@ -170,7 +170,9 @@ impl<'a, 'b, S: BaseFloat> Mul<&'b Quaternion<S>> for &'a Quaternion<S> {
} }
} }
impl<S: BaseFloat> ApproxEq<S> for Quaternion<S> { impl<S: BaseFloat> ApproxEq for Quaternion<S> {
type Epsilon = S;
#[inline] #[inline]
fn approx_eq_eps(&self, other: &Quaternion<S>, epsilon: &S) -> bool { fn approx_eq_eps(&self, other: &Quaternion<S>, epsilon: &S) -> bool {
self.s.approx_eq_eps(&other.s, epsilon) && self.s.approx_eq_eps(&other.s, epsilon) &&

View file

@ -25,7 +25,7 @@ use vector::{Vector, Vector2, Vector3};
/// A trait for a generic rotation. A rotation is a transformation that /// A trait for a generic rotation. A rotation is a transformation that
/// creates a circular motion, and preserves at least one point in the space. /// creates a circular motion, and preserves at least one point in the space.
pub trait Rotation<S: BaseFloat, P: Point<S>>: PartialEq + ApproxEq<S> + Sized { pub trait Rotation<S: BaseFloat, P: Point<S>>: PartialEq + ApproxEq<Epsilon = S> + Sized {
/// Create the identity transform (causes no transformation). /// Create the identity transform (causes no transformation).
fn one() -> Self; fn one() -> Self;
@ -206,7 +206,9 @@ impl<S: BaseFloat> Rotation<S, Point2<S>> for Basis2<S> {
fn invert_self(&mut self) { self.mat.invert_self(); } fn invert_self(&mut self) { self.mat.invert_self(); }
} }
impl<S: BaseFloat> ApproxEq<S> for Basis2<S> { impl<S: BaseFloat> ApproxEq for Basis2<S> {
type Epsilon = S;
#[inline] #[inline]
fn approx_eq_eps(&self, other: &Basis2<S>, epsilon: &S) -> bool { fn approx_eq_eps(&self, other: &Basis2<S>, epsilon: &S) -> bool {
self.mat.approx_eq_eps(&other.mat, epsilon) self.mat.approx_eq_eps(&other.mat, epsilon)
@ -288,7 +290,9 @@ impl<S: BaseFloat> Rotation<S, Point3<S>> for Basis3<S> {
fn invert_self(&mut self) { self.mat.invert_self(); } fn invert_self(&mut self) { self.mat.invert_self(); }
} }
impl<S: BaseFloat> ApproxEq<S> for Basis3<S> { impl<S: BaseFloat> ApproxEq for Basis3<S> {
type Epsilon = S;
#[inline] #[inline]
fn approx_eq_eps(&self, other: &Basis3<S>, epsilon: &S) -> bool { fn approx_eq_eps(&self, other: &Basis3<S>, epsilon: &S) -> bool {
self.mat.approx_eq_eps(&other.mat, epsilon) self.mat.approx_eq_eps(&other.mat, epsilon)

View file

@ -287,7 +287,9 @@ macro_rules! vec {
fn neg(self) -> $VectorN<S> { $VectorN::new($(-self.$field),+) } fn neg(self) -> $VectorN<S> { $VectorN::new($(-self.$field),+) }
} }
impl<S: BaseFloat> ApproxEq<S> for $VectorN<S> { impl<S: BaseFloat> ApproxEq for $VectorN<S> {
type Epsilon = S;
#[inline] #[inline]
fn approx_eq_eps(&self, other: &$VectorN<S>, epsilon: &S) -> bool { fn approx_eq_eps(&self, other: &$VectorN<S>, epsilon: &S) -> bool {
$(self.$field.approx_eq_eps(&other.$field, epsilon))&&+ $(self.$field.approx_eq_eps(&other.$field, epsilon))&&+
@ -618,7 +620,7 @@ impl<S: BaseNum> Vector4<S> {
/// Specifies geometric operations for vectors. This is only implemented for /// Specifies geometric operations for vectors. This is only implemented for
/// 2-dimensional and 3-dimensional vectors. /// 2-dimensional and 3-dimensional vectors.
pub trait EuclideanVector<S: BaseFloat>: Vector<S> pub trait EuclideanVector<S: BaseFloat>: Vector<S>
+ ApproxEq<S> + ApproxEq<Epsilon = S>
+ Sized { + Sized {
/// Returns `true` if the vector is perpendicular (at right angles) to the /// Returns `true` if the vector is perpendicular (at right angles) to the
/// other vector. /// other vector.