1 use crate::Ratio;
2 
3 use core::cmp;
4 use num_integer::Integer;
5 use num_traits::{One, Pow};
6 
7 macro_rules! pow_unsigned_impl {
8     (@ $exp:ty) => {
9         type Output = Ratio<T>;
10         #[inline]
11         fn pow(self, expon: $exp) -> Ratio<T> {
12             Ratio::new_raw(self.numer.pow(expon), self.denom.pow(expon))
13         }
14     };
15     ($exp:ty) => {
16         impl<T: Clone + Integer + Pow<$exp, Output = T>> Pow<$exp> for Ratio<T> {
17             pow_unsigned_impl!(@ $exp);
18         }
19         impl<'a, T: Clone + Integer> Pow<$exp> for &'a Ratio<T>
20         where
21             &'a T: Pow<$exp, Output = T>,
22         {
23             pow_unsigned_impl!(@ $exp);
24         }
25         impl<'b, T: Clone + Integer + Pow<$exp, Output = T>> Pow<&'b $exp> for Ratio<T> {
26             type Output = Ratio<T>;
27             #[inline]
28             fn pow(self, expon: &'b $exp) -> Ratio<T> {
29                 Pow::pow(self, *expon)
30             }
31         }
32         impl<'a, 'b, T: Clone + Integer> Pow<&'b $exp> for &'a Ratio<T>
33         where
34             &'a T: Pow<$exp, Output = T>,
35         {
36             type Output = Ratio<T>;
37             #[inline]
38             fn pow(self, expon: &'b $exp) -> Ratio<T> {
39                 Pow::pow(self, *expon)
40             }
41         }
42     };
43 }
44 pow_unsigned_impl!(u8);
45 pow_unsigned_impl!(u16);
46 pow_unsigned_impl!(u32);
47 pow_unsigned_impl!(u64);
48 pow_unsigned_impl!(u128);
49 pow_unsigned_impl!(usize);
50 
51 macro_rules! pow_signed_impl {
52     (@ &'b BigInt, BigUint) => {
53         type Output = Ratio<T>;
54         #[inline]
55         fn pow(self, expon: &'b BigInt) -> Ratio<T> {
56             match expon.sign() {
57                 Sign::NoSign => One::one(),
58                 Sign::Minus => {
59                     Pow::pow(self, expon.magnitude()).into_recip()
60                 }
61                 Sign::Plus => Pow::pow(self, expon.magnitude()),
62             }
63         }
64     };
65     (@ $exp:ty, $unsigned:ty) => {
66         type Output = Ratio<T>;
67         #[inline]
68         fn pow(self, expon: $exp) -> Ratio<T> {
69             match expon.cmp(&0) {
70                 cmp::Ordering::Equal => One::one(),
71                 cmp::Ordering::Less => {
72                     let expon = expon.wrapping_abs() as $unsigned;
73                     Pow::pow(self, expon).into_recip()
74                 }
75                 cmp::Ordering::Greater => Pow::pow(self, expon as $unsigned),
76             }
77         }
78     };
79     ($exp:ty, $unsigned:ty) => {
80         impl<T: Clone + Integer + Pow<$unsigned, Output = T>> Pow<$exp> for Ratio<T> {
81             pow_signed_impl!(@ $exp, $unsigned);
82         }
83         impl<'a, T: Clone + Integer> Pow<$exp> for &'a Ratio<T>
84         where
85             &'a T: Pow<$unsigned, Output = T>,
86         {
87             pow_signed_impl!(@ $exp, $unsigned);
88         }
89         impl<'b, T: Clone + Integer + Pow<$unsigned, Output = T>> Pow<&'b $exp> for Ratio<T> {
90             type Output = Ratio<T>;
91             #[inline]
92             fn pow(self, expon: &'b $exp) -> Ratio<T> {
93                 Pow::pow(self, *expon)
94             }
95         }
96         impl<'a, 'b, T: Clone + Integer> Pow<&'b $exp> for &'a Ratio<T>
97         where
98             &'a T: Pow<$unsigned, Output = T>,
99         {
100             type Output = Ratio<T>;
101             #[inline]
102             fn pow(self, expon: &'b $exp) -> Ratio<T> {
103                 Pow::pow(self, *expon)
104             }
105         }
106     };
107 }
108 pow_signed_impl!(i8, u8);
109 pow_signed_impl!(i16, u16);
110 pow_signed_impl!(i32, u32);
111 pow_signed_impl!(i64, u64);
112 pow_signed_impl!(i128, u128);
113 pow_signed_impl!(isize, usize);
114 
115 #[cfg(feature = "num-bigint")]
116 mod bigint {
117     use super::*;
118     use num_bigint::{BigInt, BigUint, Sign};
119 
120     impl<T: Clone + Integer + for<'b> Pow<&'b BigUint, Output = T>> Pow<BigUint> for Ratio<T> {
121         type Output = Ratio<T>;
122         #[inline]
pow(self, expon: BigUint) -> Ratio<T>123         fn pow(self, expon: BigUint) -> Ratio<T> {
124             Pow::pow(self, &expon)
125         }
126     }
127     impl<'a, T: Clone + Integer> Pow<BigUint> for &'a Ratio<T>
128     where
129         &'a T: for<'b> Pow<&'b BigUint, Output = T>,
130     {
131         type Output = Ratio<T>;
132         #[inline]
pow(self, expon: BigUint) -> Ratio<T>133         fn pow(self, expon: BigUint) -> Ratio<T> {
134             Pow::pow(self, &expon)
135         }
136     }
137     impl<'b, T: Clone + Integer + Pow<&'b BigUint, Output = T>> Pow<&'b BigUint> for Ratio<T> {
138         pow_unsigned_impl!(@ &'b BigUint);
139     }
140     impl<'a, 'b, T: Clone + Integer> Pow<&'b BigUint> for &'a Ratio<T>
141     where
142         &'a T: Pow<&'b BigUint, Output = T>,
143     {
144         pow_unsigned_impl!(@ &'b BigUint);
145     }
146 
147     impl<T: Clone + Integer + for<'b> Pow<&'b BigUint, Output = T>> Pow<BigInt> for Ratio<T> {
148         type Output = Ratio<T>;
149         #[inline]
pow(self, expon: BigInt) -> Ratio<T>150         fn pow(self, expon: BigInt) -> Ratio<T> {
151             Pow::pow(self, &expon)
152         }
153     }
154     impl<'a, T: Clone + Integer> Pow<BigInt> for &'a Ratio<T>
155     where
156         &'a T: for<'b> Pow<&'b BigUint, Output = T>,
157     {
158         type Output = Ratio<T>;
159         #[inline]
pow(self, expon: BigInt) -> Ratio<T>160         fn pow(self, expon: BigInt) -> Ratio<T> {
161             Pow::pow(self, &expon)
162         }
163     }
164     impl<'b, T: Clone + Integer + Pow<&'b BigUint, Output = T>> Pow<&'b BigInt> for Ratio<T> {
165         pow_signed_impl!(@ &'b BigInt, BigUint);
166     }
167     impl<'a, 'b, T: Clone + Integer> Pow<&'b BigInt> for &'a Ratio<T>
168     where
169         &'a T: Pow<&'b BigUint, Output = T>,
170     {
171         pow_signed_impl!(@ &'b BigInt, BigUint);
172     }
173 }
174