Skip to content

Commit c3173f7

Browse files
committed
Limit Pow using powf/powc to "std" only
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>`.
1 parent 7af251e commit c3173f7

File tree

2 files changed

+101
-13
lines changed

2 files changed

+101
-13
lines changed

src/lib.rs

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1523,7 +1523,7 @@ mod test {
15231523
#[cfg(feature = "std")]
15241524
mod float {
15251525
use super::*;
1526-
use traits::Float;
1526+
use traits::{Float, Pow};
15271527

15281528
#[test]
15291529
#[cfg_attr(target_arch = "x86", ignore)]
@@ -1629,9 +1629,11 @@ mod test {
16291629

16301630
#[test]
16311631
fn test_powf() {
1632-
let c = Complex::new(2.0, -1.0);
1633-
let r = c.powf(3.5);
1634-
assert!(close_to_tol(r, Complex::new(-0.8684746, -16.695934), 1e-5));
1632+
let c = Complex64::new(2.0, -1.0);
1633+
let expected = Complex64::new(-0.8684746, -16.695934);
1634+
assert!(close_to_tol(c.powf(3.5), expected, 1e-5));
1635+
assert!(close_to_tol(Pow::pow(c, 3.5_f64), expected, 1e-5));
1636+
assert!(close_to_tol(Pow::pow(c, 3.5_f32), expected, 1e-5));
16351637
}
16361638

16371639
#[test]

src/pow.rs

Lines changed: 95 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
11
use super::Complex;
22

3-
use std::ops::Neg;
4-
use traits::{Float, Num, One, Pow};
3+
use core::ops::Neg;
4+
#[cfg(feature = "std")]
5+
use traits::Float;
6+
use traits::{Num, One, Pow};
57

68
macro_rules! pow_impl {
79
($U:ty, $S:ty) => {
@@ -77,20 +79,94 @@ pow_impl!(usize, isize);
7779
#[cfg(has_i128)]
7880
pow_impl!(u128, i128);
7981

80-
// Note: the impls above are for `&Complex<T>`, while those below are for `Complex<T>`. This is
81-
// fine since `Float: Copy` anyway, but it's also necessary to avoid conflicting implementations.
82-
// Otherwise rustc would insist that those `Pow<{integer}>` impls could overlap with `Pow<T>` if
83-
// integers ever implement `Float`, though of course we know they won't...
82+
// Note: we can't add `impl<T: Float> Pow<T> for Complex<T>` because new blanket impls are a
83+
// breaking change. Someone could already have their own `F` and `impl Pow<F> for Complex<F>`
84+
// which would conflict. We can't even do this in a new semantic version, because we have to
85+
// gate it on the "std" feature, and features can't add breaking changes either.
86+
87+
macro_rules! powf_impl {
88+
($F:ty) => {
89+
#[cfg(feature = "std")]
90+
impl<'a, T: Float> Pow<$F> for &'a Complex<T>
91+
where
92+
$F: Into<T>,
93+
{
94+
type Output = Complex<T>;
95+
96+
#[inline]
97+
fn pow(self, exp: $F) -> Self::Output {
98+
self.powf(exp.into())
99+
}
100+
}
101+
102+
#[cfg(feature = "std")]
103+
impl<'a, 'b, T: Float> Pow<&'b $F> for &'a Complex<T>
104+
where
105+
$F: Into<T>,
106+
{
107+
type Output = Complex<T>;
108+
109+
#[inline]
110+
fn pow(self, &exp: &$F) -> Self::Output {
111+
self.powf(exp.into())
112+
}
113+
}
84114

85-
impl<T: Float> Pow<T> for Complex<T> {
115+
#[cfg(feature = "std")]
116+
impl<T: Float> Pow<$F> for Complex<T>
117+
where
118+
$F: Into<T>,
119+
{
120+
type Output = Complex<T>;
121+
122+
#[inline]
123+
fn pow(self, exp: $F) -> Self::Output {
124+
self.powf(exp.into())
125+
}
126+
}
127+
128+
#[cfg(feature = "std")]
129+
impl<'b, T: Float> Pow<&'b $F> for Complex<T>
130+
where
131+
$F: Into<T>,
132+
{
133+
type Output = Complex<T>;
134+
135+
#[inline]
136+
fn pow(self, &exp: &$F) -> Self::Output {
137+
self.powf(exp.into())
138+
}
139+
}
140+
};
141+
}
142+
143+
powf_impl!(f32);
144+
powf_impl!(f64);
145+
146+
// These blanket impls are OK, because both the target type and the trait parameter would be
147+
// foreign to anyone else trying to implement something that would overlap, raising E0117.
148+
149+
#[cfg(feature = "std")]
150+
impl<'a, T: Float> Pow<Complex<T>> for &'a Complex<T> {
86151
type Output = Complex<T>;
87152

88153
#[inline]
89-
fn pow(self, exp: T) -> Self::Output {
90-
self.powf(exp)
154+
fn pow(self, exp: Complex<T>) -> Self::Output {
155+
self.powc(exp)
91156
}
92157
}
93158

159+
#[cfg(feature = "std")]
160+
impl<'a, 'b, T: Float> Pow<&'b Complex<T>> for &'a Complex<T> {
161+
type Output = Complex<T>;
162+
163+
#[inline]
164+
fn pow(self, &exp: &'b Complex<T>) -> Self::Output {
165+
self.powc(exp)
166+
}
167+
}
168+
169+
#[cfg(feature = "std")]
94170
impl<T: Float> Pow<Complex<T>> for Complex<T> {
95171
type Output = Complex<T>;
96172

@@ -99,3 +175,13 @@ impl<T: Float> Pow<Complex<T>> for Complex<T> {
99175
self.powc(exp)
100176
}
101177
}
178+
179+
#[cfg(feature = "std")]
180+
impl<'b, T: Float> Pow<&'b Complex<T>> for Complex<T> {
181+
type Output = Complex<T>;
182+
183+
#[inline]
184+
fn pow(self, &exp: &'b Complex<T>) -> Self::Output {
185+
self.powc(exp)
186+
}
187+
}

0 commit comments

Comments
 (0)