use errors::ErrorKind;
use lazy::SimpleAssert;
use num_traits::{Float, Zero};
use std::fmt::Debug;
pub trait FloatMust: Debug + Float {
fn must_be_nan(self) -> SimpleAssert<Self> {
if self.is_nan() {
self.into()
} else {
ErrorKind::MustBeNan.but_got(self)
}
}
fn must_not_be_nan(self) -> SimpleAssert<Self> {
if !self.is_nan() {
self.into()
} else {
ErrorKind::MustNotBeNan.but_got(self)
}
}
fn must_be_close_to(self, expected: Self, epsilon: Self) -> SimpleAssert<Self> {
if is_close_to(self, expected, epsilon) {
self.into()
} else {
ErrorKind::Msg(format!("must be close to {:?} (with in epsilon={:?})",
expected,
epsilon))
.but_got(self)
}
}
fn must_not_be_close_to(self, expected: Self, epsilon: Self) -> SimpleAssert<Self> {
if !is_close_to(self, expected, epsilon) {
self.into()
} else {
ErrorKind::Msg(format!("must not be close to {:?} (with in epsilon={:?})",
expected,
epsilon))
.but_got(self)
}
}
}
impl<V> FloatMust for V where V: Debug + Float {}
fn is_close_to<T: Float>(got: T, expected: T, epsilon: T) -> bool {
let a = expected.abs();
let b = got.abs();
let d = (a - b).abs();
let close =
a == b
|| ((a == Zero::zero() || b == Zero::zero() || d < Float::min_positive_value()) &&
d < (epsilon * Float::min_positive_value()))
|| d / (a + b).min(Float::max_value()) < epsilon;
close
}
fn _assert() {
fn implemented_for<T: FloatMust>() {}
implemented_for::<f32>();
implemented_for::<f64>();
}