Skip to content

Commit

Permalink
Limit Pow using powf/powc to "std" only
Browse files Browse the repository at this point in the history
We also can't have a blanket impl `Pow<T>`, as it's a breaking change.
Instead, we add `Pow<f32>` and `Pow<f64>` where those are `Into<T>`.
  • Loading branch information
cuviper committed Jun 6, 2019
1 parent 7af251e commit c3173f7
Show file tree
Hide file tree
Showing 2 changed files with 101 additions and 13 deletions.
10 changes: 6 additions & 4 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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)]
Expand Down Expand Up @@ -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]
Expand Down
104 changes: 95 additions & 9 deletions src/pow.rs
Original file line number Diff line number Diff line change
@@ -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) => {
Expand Down Expand Up @@ -77,20 +79,94 @@ pow_impl!(usize, isize);
#[cfg(has_i128)]
pow_impl!(u128, i128);

// Note: the impls above are for `&Complex<T>`, while those below are for `Complex<T>`. 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<T>` if
// integers ever implement `Float`, though of course we know they won't...
// Note: we can't add `impl<T: Float> Pow<T> for Complex<T>` because new blanket impls are a
// breaking change. Someone could already have their own `F` and `impl Pow<F> for Complex<F>`
// 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<T>
where
$F: Into<T>,
{
type Output = Complex<T>;

#[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<T>
where
$F: Into<T>,
{
type Output = Complex<T>;

#[inline]
fn pow(self, &exp: &$F) -> Self::Output {
self.powf(exp.into())
}
}

impl<T: Float> Pow<T> for Complex<T> {
#[cfg(feature = "std")]
impl<T: Float> Pow<$F> for Complex<T>
where
$F: Into<T>,
{
type Output = Complex<T>;

#[inline]
fn pow(self, exp: $F) -> Self::Output {
self.powf(exp.into())
}
}

#[cfg(feature = "std")]
impl<'b, T: Float> Pow<&'b $F> for Complex<T>
where
$F: Into<T>,
{
type Output = Complex<T>;

#[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<Complex<T>> for &'a Complex<T> {
type Output = Complex<T>;

#[inline]
fn pow(self, exp: T) -> Self::Output {
self.powf(exp)
fn pow(self, exp: Complex<T>) -> Self::Output {
self.powc(exp)
}
}

#[cfg(feature = "std")]
impl<'a, 'b, T: Float> Pow<&'b Complex<T>> for &'a Complex<T> {
type Output = Complex<T>;

#[inline]
fn pow(self, &exp: &'b Complex<T>) -> Self::Output {
self.powc(exp)
}
}

#[cfg(feature = "std")]
impl<T: Float> Pow<Complex<T>> for Complex<T> {
type Output = Complex<T>;

Expand All @@ -99,3 +175,13 @@ impl<T: Float> Pow<Complex<T>> for Complex<T> {
self.powc(exp)
}
}

#[cfg(feature = "std")]
impl<'b, T: Float> Pow<&'b Complex<T>> for Complex<T> {
type Output = Complex<T>;

#[inline]
fn pow(self, &exp: &'b Complex<T>) -> Self::Output {
self.powc(exp)
}
}

0 comments on commit c3173f7

Please sign in to comment.