From c3173f70c2a0969503ce64c0ca103299bdf239f0 Mon Sep 17 00:00:00 2001 From: Josh Stone Date: Thu, 6 Jun 2019 11:41:49 -0700 Subject: [PATCH] Limit Pow using powf/powc to "std" only We also can't have a blanket impl `Pow`, as it's a breaking change. Instead, we add `Pow` and `Pow` where those are `Into`. --- src/lib.rs | 10 +++--- src/pow.rs | 104 ++++++++++++++++++++++++++++++++++++++++++++++++----- 2 files changed, 101 insertions(+), 13 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 78d5f79..caa0518 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1523,7 +1523,7 @@ mod test { #[cfg(feature = "std")] mod float { use super::*; - use traits::Float; + use traits::{Float, Pow}; #[test] #[cfg_attr(target_arch = "x86", ignore)] @@ -1629,9 +1629,11 @@ mod test { #[test] fn test_powf() { - let c = Complex::new(2.0, -1.0); - let r = c.powf(3.5); - assert!(close_to_tol(r, Complex::new(-0.8684746, -16.695934), 1e-5)); + let c = Complex64::new(2.0, -1.0); + let expected = Complex64::new(-0.8684746, -16.695934); + assert!(close_to_tol(c.powf(3.5), expected, 1e-5)); + assert!(close_to_tol(Pow::pow(c, 3.5_f64), expected, 1e-5)); + assert!(close_to_tol(Pow::pow(c, 3.5_f32), expected, 1e-5)); } #[test] diff --git a/src/pow.rs b/src/pow.rs index f76006d..2f6b5ba 100644 --- a/src/pow.rs +++ b/src/pow.rs @@ -1,7 +1,9 @@ use super::Complex; -use std::ops::Neg; -use traits::{Float, Num, One, Pow}; +use core::ops::Neg; +#[cfg(feature = "std")] +use traits::Float; +use traits::{Num, One, Pow}; macro_rules! pow_impl { ($U:ty, $S:ty) => { @@ -77,20 +79,94 @@ pow_impl!(usize, isize); #[cfg(has_i128)] pow_impl!(u128, i128); -// Note: the impls above are for `&Complex`, while those below are for `Complex`. This is -// fine since `Float: Copy` anyway, but it's also necessary to avoid conflicting implementations. -// Otherwise rustc would insist that those `Pow<{integer}>` impls could overlap with `Pow` if -// integers ever implement `Float`, though of course we know they won't... +// Note: we can't add `impl Pow for Complex` because new blanket impls are a +// breaking change. Someone could already have their own `F` and `impl Pow for Complex` +// which would conflict. We can't even do this in a new semantic version, because we have to +// gate it on the "std" feature, and features can't add breaking changes either. + +macro_rules! powf_impl { + ($F:ty) => { + #[cfg(feature = "std")] + impl<'a, T: Float> Pow<$F> for &'a Complex + where + $F: Into, + { + type Output = Complex; + + #[inline] + fn pow(self, exp: $F) -> Self::Output { + self.powf(exp.into()) + } + } + + #[cfg(feature = "std")] + impl<'a, 'b, T: Float> Pow<&'b $F> for &'a Complex + where + $F: Into, + { + type Output = Complex; + + #[inline] + fn pow(self, &exp: &$F) -> Self::Output { + self.powf(exp.into()) + } + } -impl Pow for Complex { + #[cfg(feature = "std")] + impl Pow<$F> for Complex + where + $F: Into, + { + type Output = Complex; + + #[inline] + fn pow(self, exp: $F) -> Self::Output { + self.powf(exp.into()) + } + } + + #[cfg(feature = "std")] + impl<'b, T: Float> Pow<&'b $F> for Complex + where + $F: Into, + { + type Output = Complex; + + #[inline] + fn pow(self, &exp: &$F) -> Self::Output { + self.powf(exp.into()) + } + } + }; +} + +powf_impl!(f32); +powf_impl!(f64); + +// These blanket impls are OK, because both the target type and the trait parameter would be +// foreign to anyone else trying to implement something that would overlap, raising E0117. + +#[cfg(feature = "std")] +impl<'a, T: Float> Pow> for &'a Complex { type Output = Complex; #[inline] - fn pow(self, exp: T) -> Self::Output { - self.powf(exp) + fn pow(self, exp: Complex) -> Self::Output { + self.powc(exp) } } +#[cfg(feature = "std")] +impl<'a, 'b, T: Float> Pow<&'b Complex> for &'a Complex { + type Output = Complex; + + #[inline] + fn pow(self, &exp: &'b Complex) -> Self::Output { + self.powc(exp) + } +} + +#[cfg(feature = "std")] impl Pow> for Complex { type Output = Complex; @@ -99,3 +175,13 @@ impl Pow> for Complex { self.powc(exp) } } + +#[cfg(feature = "std")] +impl<'b, T: Float> Pow<&'b Complex> for Complex { + type Output = Complex; + + #[inline] + fn pow(self, &exp: &'b Complex) -> Self::Output { + self.powc(exp) + } +}