use crate::Ratio; use core::cmp; use num_integer::Integer; use num_traits::{One, Pow}; macro_rules! pow_unsigned_impl { (@ $exp:ty) => { type Output = Ratio; #[inline] fn pow(self, expon: $exp) -> Ratio { Ratio::new_raw(self.numer.pow(expon), self.denom.pow(expon)) } }; ($exp:ty) => { impl> Pow<$exp> for Ratio { pow_unsigned_impl!(@ $exp); } impl<'a, T: Clone + Integer> Pow<$exp> for &'a Ratio where &'a T: Pow<$exp, Output = T>, { pow_unsigned_impl!(@ $exp); } impl<'b, T: Clone + Integer + Pow<$exp, Output = T>> Pow<&'b $exp> for Ratio { type Output = Ratio; #[inline] fn pow(self, expon: &'b $exp) -> Ratio { Pow::pow(self, *expon) } } impl<'a, 'b, T: Clone + Integer> Pow<&'b $exp> for &'a Ratio where &'a T: Pow<$exp, Output = T>, { type Output = Ratio; #[inline] fn pow(self, expon: &'b $exp) -> Ratio { Pow::pow(self, *expon) } } }; } pow_unsigned_impl!(u8); pow_unsigned_impl!(u16); pow_unsigned_impl!(u32); pow_unsigned_impl!(u64); pow_unsigned_impl!(u128); pow_unsigned_impl!(usize); macro_rules! pow_signed_impl { (@ &'b BigInt, BigUint) => { type Output = Ratio; #[inline] fn pow(self, expon: &'b BigInt) -> Ratio { match expon.sign() { Sign::NoSign => One::one(), Sign::Minus => { Pow::pow(self, expon.magnitude()).into_recip() } Sign::Plus => Pow::pow(self, expon.magnitude()), } } }; (@ $exp:ty, $unsigned:ty) => { type Output = Ratio; #[inline] fn pow(self, expon: $exp) -> Ratio { match expon.cmp(&0) { cmp::Ordering::Equal => One::one(), cmp::Ordering::Less => { let expon = expon.wrapping_abs() as $unsigned; Pow::pow(self, expon).into_recip() } cmp::Ordering::Greater => Pow::pow(self, expon as $unsigned), } } }; ($exp:ty, $unsigned:ty) => { impl> Pow<$exp> for Ratio { pow_signed_impl!(@ $exp, $unsigned); } impl<'a, T: Clone + Integer> Pow<$exp> for &'a Ratio where &'a T: Pow<$unsigned, Output = T>, { pow_signed_impl!(@ $exp, $unsigned); } impl<'b, T: Clone + Integer + Pow<$unsigned, Output = T>> Pow<&'b $exp> for Ratio { type Output = Ratio; #[inline] fn pow(self, expon: &'b $exp) -> Ratio { Pow::pow(self, *expon) } } impl<'a, 'b, T: Clone + Integer> Pow<&'b $exp> for &'a Ratio where &'a T: Pow<$unsigned, Output = T>, { type Output = Ratio; #[inline] fn pow(self, expon: &'b $exp) -> Ratio { Pow::pow(self, *expon) } } }; } pow_signed_impl!(i8, u8); pow_signed_impl!(i16, u16); pow_signed_impl!(i32, u32); pow_signed_impl!(i64, u64); pow_signed_impl!(i128, u128); pow_signed_impl!(isize, usize); #[cfg(feature = "num-bigint")] mod bigint { use super::*; use num_bigint::{BigInt, BigUint, Sign}; impl Pow<&'b BigUint, Output = T>> Pow for Ratio { type Output = Ratio; #[inline] fn pow(self, expon: BigUint) -> Ratio { Pow::pow(self, &expon) } } impl<'a, T: Clone + Integer> Pow for &'a Ratio where &'a T: for<'b> Pow<&'b BigUint, Output = T>, { type Output = Ratio; #[inline] fn pow(self, expon: BigUint) -> Ratio { Pow::pow(self, &expon) } } impl<'b, T: Clone + Integer + Pow<&'b BigUint, Output = T>> Pow<&'b BigUint> for Ratio { pow_unsigned_impl!(@ &'b BigUint); } impl<'a, 'b, T: Clone + Integer> Pow<&'b BigUint> for &'a Ratio where &'a T: Pow<&'b BigUint, Output = T>, { pow_unsigned_impl!(@ &'b BigUint); } impl Pow<&'b BigUint, Output = T>> Pow for Ratio { type Output = Ratio; #[inline] fn pow(self, expon: BigInt) -> Ratio { Pow::pow(self, &expon) } } impl<'a, T: Clone + Integer> Pow for &'a Ratio where &'a T: for<'b> Pow<&'b BigUint, Output = T>, { type Output = Ratio; #[inline] fn pow(self, expon: BigInt) -> Ratio { Pow::pow(self, &expon) } } impl<'b, T: Clone + Integer + Pow<&'b BigUint, Output = T>> Pow<&'b BigInt> for Ratio { pow_signed_impl!(@ &'b BigInt, BigUint); } impl<'a, 'b, T: Clone + Integer> Pow<&'b BigInt> for &'a Ratio where &'a T: Pow<&'b BigUint, Output = T>, { pow_signed_impl!(@ &'b BigInt, BigUint); } }