diff --git a/Cargo.toml b/Cargo.toml index cf29205..f569571 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "ordered-float" -version = "2.2.0" +version = "2.3.0" authors = ["Jonathan Reem ", "Matt Brubeck "] license = "MIT" description = "Wrappers for total ordering on floats" diff --git a/src/lib.rs b/src/lib.rs index 404c169..40ac9b6 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -173,85 +173,96 @@ impl DerefMut for OrderedFloat { impl Eq for OrderedFloat {} -impl Add for OrderedFloat { - type Output = OrderedFloat; +macro_rules! impl_ordered_float_binop { + ($imp:ident, $method:ident) => { + impl $imp for OrderedFloat { + type Output = OrderedFloat; + + #[inline] + fn $method(self, other: Self) -> Self::Output { + OrderedFloat((self.0).$method(other.0)) + } + } - fn add(self, other: Self) -> Self::Output { - OrderedFloat(self.0 + other.0) - } -} + impl $imp for OrderedFloat { + type Output = OrderedFloat; -impl Add for OrderedFloat { - type Output = OrderedFloat; + #[inline] + fn $method(self, other: T) -> Self::Output { + OrderedFloat((self.0).$method(other)) + } + } - fn add(self, other: T) -> Self::Output { - OrderedFloat(self.0 + other) - } -} + impl<'a, T> $imp<&'a T> for OrderedFloat where T: $imp<&'a T> { + type Output = OrderedFloat<>::Output>; -impl Sub for OrderedFloat { - type Output = OrderedFloat; + #[inline] + fn $method(self, other: &'a T) -> Self::Output { + OrderedFloat((self.0).$method(other)) + } + } - fn sub(self, other: Self) -> Self::Output { - OrderedFloat(self.0 - other.0) - } -} + impl<'a, T> $imp<&'a Self> for OrderedFloat where T: $imp<&'a T> { + type Output = OrderedFloat<>::Output>; -impl Sub for OrderedFloat { - type Output = OrderedFloat; + #[inline] + fn $method(self, other: &'a Self) -> Self::Output { + OrderedFloat((self.0).$method(&other.0)) + } + } - fn sub(self, other: T) -> Self::Output { - OrderedFloat(self.0 - other) - } -} + impl<'a, T> $imp for &'a OrderedFloat where &'a T: $imp { + type Output = OrderedFloat<<&'a T as $imp>::Output>; -impl Mul for OrderedFloat { - type Output = OrderedFloat; + #[inline] + fn $method(self, other: Self) -> Self::Output { + OrderedFloat((self.0).$method(&other.0)) + } + } - fn mul(self, other: Self) -> Self::Output { - OrderedFloat(self.0 * other.0) - } -} + impl<'a, T> $imp> for &'a OrderedFloat where &'a T: $imp { + type Output = OrderedFloat<<&'a T as $imp>::Output>; -impl Mul for OrderedFloat { - type Output = OrderedFloat; + #[inline] + fn $method(self, other: OrderedFloat) -> Self::Output { + OrderedFloat((self.0).$method(other.0)) + } + } - fn mul(self, other: T) -> Self::Output { - OrderedFloat(self.0 * other) - } -} + impl<'a, T> $imp for &'a OrderedFloat where &'a T: $imp { + type Output = OrderedFloat<<&'a T as $imp>::Output>; -impl Div for OrderedFloat { - type Output = OrderedFloat; + #[inline] + fn $method(self, other: T) -> Self::Output { + OrderedFloat((self.0).$method(other)) + } + } - fn div(self, other: Self) -> Self::Output { - OrderedFloat(self.0 / other.0) - } -} + impl<'a, T> $imp<&'a T> for &'a OrderedFloat where &'a T: $imp { + type Output = OrderedFloat<<&'a T as $imp>::Output>; -impl Div for OrderedFloat { - type Output = OrderedFloat; + #[inline] + fn $method(self, other: &'a T) -> Self::Output { + OrderedFloat((self.0).$method(other)) + } + } - fn div(self, other: T) -> Self::Output { - OrderedFloat(self.0 / other) - } -} + impl<'a, T> $imp<&'a Self> for &'a OrderedFloat where &'a T: $imp { + type Output = OrderedFloat<<&'a T as $imp>::Output>; -impl Rem for OrderedFloat { - type Output = OrderedFloat; - - fn rem(self, other: Self) -> Self::Output { - OrderedFloat(self.0 % other.0) + #[inline] + fn $method(self, other: &'a Self) -> Self::Output { + OrderedFloat((self.0).$method(&other.0)) + } + } } } -impl Rem for OrderedFloat { - type Output = OrderedFloat; - - fn rem(self, other: T) -> Self::Output { - OrderedFloat(self.0 % other) - } -} +impl_ordered_float_binop!{Add, add} +impl_ordered_float_binop!{Sub, sub} +impl_ordered_float_binop!{Mul, mul} +impl_ordered_float_binop!{Div, div} +impl_ordered_float_binop!{Rem, rem} impl Bounded for OrderedFloat { fn min_value() -> Self { @@ -288,6 +299,14 @@ impl Neg for OrderedFloat { } } +impl<'a, T> Neg for &'a OrderedFloat where &'a T: Neg { + type Output = OrderedFloat<<&'a T as Neg>::Output>; + + fn neg(self) -> Self::Output { + OrderedFloat(-(&self.0)) + } +} + impl Zero for OrderedFloat { fn zero() -> Self { OrderedFloat(T::zero()) } @@ -549,17 +568,6 @@ impl PartialEq for NotNan { } } -/// Adds two NotNans. -/// -/// Panics if the computation results in NaN -impl Add for NotNan { - type Output = Self; - - fn add(self, other: Self) -> Self { - self + other.0 - } -} - /// Adds a float directly. /// /// Panics if the provided value is NaN or the computation results in NaN @@ -571,22 +579,9 @@ impl Add for NotNan { } } -impl AddAssign for NotNan { - fn add_assign(&mut self, other: Self) { - *self += other.0; - } -} - /// Adds a float directly. /// /// Panics if the provided value is NaN. -impl AddAssign for NotNan { - fn add_assign(&mut self, other: T) { - *self = *self + other; - } -} - - impl Sum for NotNan { fn sum>>(iter: I) -> Self { NotNan::new(iter.map(|v| v.0).sum()).expect("Sum resulted in NaN") @@ -599,14 +594,6 @@ impl<'a, T: Float + Sum + 'a> Sum<&'a NotNan> for NotNan { } } -impl Sub for NotNan { - type Output = Self; - - fn sub(self, other: Self) -> Self { - self - other.0 - } -} - /// Subtracts a float directly. /// /// Panics if the provided value is NaN or the computation results in NaN @@ -618,29 +605,6 @@ impl Sub for NotNan { } } -impl SubAssign for NotNan { - fn sub_assign(&mut self, other: Self) { - *self -= other.0 - } -} - -/// Subtracts a float directly. -/// -/// Panics if the provided value is NaN or the computation results in NaN -impl SubAssign for NotNan { - fn sub_assign(&mut self, other: T) { - *self = *self - other; - } -} - -impl Mul for NotNan { - type Output = Self; - - fn mul(self, other: Self) -> Self { - self * other.0 - } -} - /// Multiplies a float directly. /// /// Panics if the provided value is NaN or the computation results in NaN @@ -652,21 +616,6 @@ impl Mul for NotNan { } } -impl MulAssign for NotNan { - fn mul_assign(&mut self, other: Self) { - *self *= other.0 - } -} - -/// Multiplies a float directly. -/// -/// Panics if the provided value is NaN. -impl MulAssign for NotNan { - fn mul_assign(&mut self, other: T) { - *self = *self * other; - } -} - impl Product for NotNan { fn product>>(iter: I) -> Self { NotNan::new(iter.map(|v| v.0).product()).expect("Product resulted in NaN") @@ -679,14 +628,6 @@ impl<'a, T: Float + Product + 'a> Product<&'a NotNan> for NotNan { } } -impl Div for NotNan { - type Output = Self; - - fn div(self, other: Self) -> Self { - self / other.0 - } -} - /// Divides a float directly. /// /// Panics if the provided value is NaN or the computation results in NaN @@ -698,29 +639,6 @@ impl Div for NotNan { } } -impl DivAssign for NotNan { - fn div_assign(&mut self, other: Self) { - *self /= other.0; - } -} - -/// Divides a float directly. -/// -/// Panics if the provided value is NaN or the computation results in NaN -impl DivAssign for NotNan { - fn div_assign(&mut self, other: T) { - *self = *self / other; - } -} - -impl Rem for NotNan { - type Output = Self; - - fn rem(self, other: Self) -> Self { - self % other.0 - } -} - /// Calculates `%` with a float directly. /// /// Panics if the provided value is NaN or the computation results in NaN @@ -732,21 +650,96 @@ impl Rem for NotNan { } } -impl RemAssign for NotNan { - fn rem_assign(&mut self, other: Self) { - *self %= other.0 - } -} +macro_rules! impl_not_nan_binop { + ($imp:ident, $method:ident, $assign_imp:ident, $assign_method:ident) => { + impl $imp for NotNan { + type Output = Self; -/// Calculates `%=` with a float directly. -/// -/// Panics if the provided value is NaN or the computation results in NaN -impl RemAssign for NotNan { - fn rem_assign(&mut self, other: T) { - *self = *self % other; + fn $method(self, other: Self) -> Self { + self.$method(other.0) + } + } + + impl $imp<&T> for NotNan { + type Output = NotNan; + + fn $method(self, other: &T) -> Self::Output { + self.$method(*other) + } + } + + impl $imp<&Self> for NotNan { + type Output = NotNan; + + fn $method(self, other: &Self) -> Self::Output { + self.$method(other.0) + } + } + + impl $imp for &NotNan { + type Output = NotNan; + + fn $method(self, other: Self) -> Self::Output { + (*self).$method(other.0) + } + } + + impl $imp> for &NotNan { + type Output = NotNan; + + fn $method(self, other: NotNan) -> Self::Output { + (*self).$method(other.0) + } + } + + impl $imp for &NotNan { + type Output = NotNan; + + fn $method(self, other: T) -> Self::Output { + (*self).$method(other) + } + } + + impl $imp<&T> for &NotNan { + type Output = NotNan; + + fn $method(self, other: &T) -> Self::Output { + (*self).$method(*other) + } + } + + impl $assign_imp for NotNan { + fn $assign_method(&mut self, other: T) { + *self = (*self).$method(other); + } + } + + impl $assign_imp<&T> for NotNan { + fn $assign_method(&mut self, other: &T) { + *self = (*self).$method(*other); + } + } + + impl $assign_imp for NotNan { + fn $assign_method(&mut self, other: Self) { + (*self).$assign_method(other.0); + } + } + + impl $assign_imp<&Self> for NotNan { + fn $assign_method(&mut self, other: &Self) { + (*self).$assign_method(other.0); + } + } } } +impl_not_nan_binop!{Add, add, AddAssign, add_assign} +impl_not_nan_binop!{Sub, sub, SubAssign, sub_assign} +impl_not_nan_binop!{Mul, mul, MulAssign, mul_assign} +impl_not_nan_binop!{Div, div, DivAssign, div_assign} +impl_not_nan_binop!{Rem, rem, RemAssign, rem_assign} + impl Neg for NotNan { type Output = Self; @@ -755,6 +748,14 @@ impl Neg for NotNan { } } +impl Neg for &NotNan { + type Output = NotNan; + + fn neg(self) -> Self::Output { + NotNan(-self.0) + } +} + /// An error indicating an attempt to construct NotNan from a NaN #[derive(Copy, Clone, PartialEq, Eq, Debug)] pub struct FloatIsNan; diff --git a/tests/test.rs b/tests/test.rs index 0157ceb..325b4b1 100644 --- a/tests/test.rs +++ b/tests/test.rs @@ -541,6 +541,91 @@ fn test_add_fails_on_nan() { let _c = a + b; } +#[test] +#[should_panic] +fn test_add_fails_on_nan_ref() { + let a = not_nan(std::f32::INFINITY); + let b = not_nan(std::f32::NEG_INFINITY); + let _c = a + &b; +} + +#[test] +#[should_panic] +fn test_add_fails_on_nan_ref_ref() { + let a = not_nan(std::f32::INFINITY); + let b = not_nan(std::f32::NEG_INFINITY); + let _c = &a + &b; +} + +#[test] +#[should_panic] +fn test_add_fails_on_nan_t_ref() { + let a = not_nan(std::f32::INFINITY); + let b = std::f32::NEG_INFINITY; + let _c = a + &b; +} + +#[test] +#[should_panic] +fn test_add_fails_on_nan_ref_t_ref() { + let a = not_nan(std::f32::INFINITY); + let b = std::f32::NEG_INFINITY; + let _c = &a + &b; +} + +#[test] +#[should_panic] +fn test_add_fails_on_nan_ref_t() { + let a = not_nan(std::f32::INFINITY); + let b = std::f32::NEG_INFINITY; + let _c = &a + b; +} + +#[test] +#[should_panic] +fn test_add_assign_fails_on_nan_ref() { + let mut a = not_nan(std::f32::INFINITY); + let b = not_nan(std::f32::NEG_INFINITY); + a += &b; +} + +#[test] +#[should_panic] +fn test_add_assign_fails_on_nan_t_ref() { + let mut a = not_nan(std::f32::INFINITY); + let b = std::f32::NEG_INFINITY; + a += &b; +} + +#[test] +#[should_panic] +fn test_add_assign_fails_on_nan_t() { + let mut a = not_nan(std::f32::INFINITY); + let b = std::f32::NEG_INFINITY; + a += b; +} + +#[test] +fn add() { + assert_eq!(not_nan(0.0) + not_nan(0.0), 0.0); + assert_eq!(not_nan(0.0) + ¬_nan(0.0), 0.0); + assert_eq!(¬_nan(0.0) + not_nan(0.0), 0.0); + assert_eq!(¬_nan(0.0) + ¬_nan(0.0), 0.0); + assert_eq!(not_nan(0.0) + 0.0, 0.0); + assert_eq!(not_nan(0.0) + &0.0, 0.0); + assert_eq!(¬_nan(0.0) + 0.0, 0.0); + assert_eq!(¬_nan(0.0) + &0.0, 0.0); + + assert_eq!(OrderedFloat(0.0) + OrderedFloat(0.0), 0.0); + assert_eq!(OrderedFloat(0.0) + &OrderedFloat(0.0), 0.0); + assert_eq!(&OrderedFloat(0.0) + OrderedFloat(0.0), 0.0); + assert_eq!(&OrderedFloat(0.0) + &OrderedFloat(0.0), 0.0); + assert_eq!(OrderedFloat(0.0) + 0.0, 0.0); + assert_eq!(OrderedFloat(0.0) + &0.0, 0.0); + assert_eq!(&OrderedFloat(0.0) + 0.0, 0.0); + assert_eq!(&OrderedFloat(0.0) + &0.0, 0.0); +} + #[test] fn ordered_f32_neg() { assert_eq!(OrderedFloat(-7.0f32), -OrderedFloat(7.0f32));