diff --git a/ratio_ops/src/ratio.rs b/ratio_ops/src/ratio.rs index 6ae0ad2..7f806da 100644 --- a/ratio_ops/src/ratio.rs +++ b/ratio_ops/src/ratio.rs @@ -1,10 +1,171 @@ #[derive(Clone,Copy,Debug,Hash)] pub struct Ratio<Num,Den>{ - pub(crate)num:Num, - pub(crate)den:Den, + pub num:Num, + pub den:Den, } impl<Num,Den> Ratio<Num,Den>{ + #[inline(always)] pub const fn new(num:Num,den:Den)->Self{ Self{num,den} } } + +impl<Num,Den> Ratio<Num,Den> + where + Num:core::ops::Div<Den>, +{ + #[inline] + pub fn divide(num:Num,den:Den)-><Num as core::ops::Div<Den>>::Output{ + num/den + } +} + +//take care to use the ratio methods to avoid nested ratios + +impl<LhsNum,LhsDen> Ratio<LhsNum,LhsDen>{ + #[inline] + pub fn mul_ratio<RhsNum,RhsDen>(self,rhs:Ratio<RhsNum,RhsDen>)->Ratio<<LhsNum as core::ops::Mul<RhsNum>>::Output,<LhsDen as core::ops::Mul<RhsDen>>::Output> + where + LhsNum:core::ops::Mul<RhsNum>, + LhsDen:core::ops::Mul<RhsDen>, + { + Ratio::new(self.num*rhs.num,self.den*rhs.den) + } + #[inline] + pub fn div_ratio<RhsNum,RhsDen>(self,rhs:Ratio<RhsNum,RhsDen>)->Ratio<<LhsNum as core::ops::Mul<RhsDen>>::Output,<LhsDen as core::ops::Mul<RhsNum>>::Output> + where + LhsNum:core::ops::Mul<RhsDen>, + LhsDen:core::ops::Mul<RhsNum>, + { + Ratio::new(self.num*rhs.den,self.den*rhs.num) + } +} +macro_rules! impl_ratio_method { + ($trait:ident, $method:ident, $ratio_method:ident) => { + impl<LhsNum,LhsDen> Ratio<LhsNum,LhsDen>{ + #[inline] + pub fn $ratio_method<RhsNum,RhsDen,LhsCrossMul,RhsCrossMul>(self,rhs:Ratio<RhsNum,RhsDen>)->Ratio<<LhsCrossMul as core::ops::$trait<RhsCrossMul>>::Output,<LhsDen as core::ops::Mul<RhsDen>>::Output> + where + LhsNum:core::ops::Mul<RhsDen,Output=LhsCrossMul>, + LhsDen:core::ops::Mul<RhsNum,Output=RhsCrossMul>, + LhsDen:core::ops::Mul<RhsDen>, + LhsDen:Copy, + RhsDen:Copy, + LhsCrossMul:core::ops::$trait<RhsCrossMul>, + { + Ratio::new((self.num*rhs.den).$method(self.den*rhs.num),self.den*rhs.den) + } + } + }; +} +impl_ratio_method!(Add,add,add_ratio); +impl_ratio_method!(Sub,sub,sub_ratio); +impl_ratio_method!(Rem,rem,rem_ratio); + +/* generic rhs mul is not possible! +impl<Lhs,RhsNum,RhsDen> core::ops::Mul<Ratio<RhsNum,RhsDen>> for Lhs + where + Lhs:core::ops::Mul<RhsNum>, +{ + type Output=Ratio<<Lhs as core::ops::Mul<RhsNum>>::Output,RhsDen>; + #[inline] + fn mul(self,rhs:Ratio<RhsNum,RhsDen>)->Self::Output{ + Ratio::new(self*rhs.num,rhs.den) + } +} +*/ + +//operators + +impl<LhsNum,LhsDen> core::ops::Neg for Ratio<LhsNum,LhsDen> + where + LhsNum:core::ops::Neg, +{ + type Output=Ratio<<LhsNum as core::ops::Neg>::Output,LhsDen>; + #[inline] + fn neg(self)->Self::Output{ + Ratio::new(-self.num,self.den) + } +} +impl<LhsNum,LhsDen,Rhs> core::ops::Mul<Rhs> for Ratio<LhsNum,LhsDen> + where + LhsNum:core::ops::Mul<Rhs>, +{ + type Output=Ratio<<LhsNum as core::ops::Mul<Rhs>>::Output,LhsDen>; + #[inline] + fn mul(self,rhs:Rhs)->Self::Output{ + Ratio::new(self.num*rhs,self.den) + } +} +impl<LhsNum,LhsDen,Rhs> core::ops::Div<Rhs> for Ratio<LhsNum,LhsDen> + where + LhsDen:core::ops::Mul<Rhs>, +{ + type Output=Ratio<LhsNum,<LhsDen as core::ops::Mul<Rhs>>::Output>; + #[inline] + fn div(self,rhs:Rhs)->Self::Output{ + Ratio::new(self.num,self.den*rhs) + } +} + +macro_rules! impl_ratio_operator { + ($trait:ident, $method:ident) => { + impl<LhsNum,LhsDen,Rhs,Intermediate> core::ops::$trait<Rhs> for Ratio<LhsNum,LhsDen> + where + LhsNum:core::ops::$trait<Intermediate>, + LhsDen:Copy, + Rhs:core::ops::Mul<LhsDen,Output=Intermediate>, + { + type Output=Ratio<<LhsNum as core::ops::$trait<Intermediate>>::Output,LhsDen>; + #[inline] + fn $method(self,rhs:Rhs)->Self::Output{ + Ratio::new(self.num.$method(rhs*self.den),self.den) + } + } + }; +} + +impl_ratio_operator!(Add,add); +impl_ratio_operator!(Sub,sub); +impl_ratio_operator!(Rem,rem); + +//assign operators + +impl<LhsNum,LhsDen,Rhs> core::ops::MulAssign<Rhs> for Ratio<LhsNum,LhsDen> + where + LhsNum:core::ops::MulAssign<Rhs>, +{ + #[inline] + fn mul_assign(&mut self,rhs:Rhs){ + self.num*=rhs; + } +} +impl<LhsNum,LhsDen,Rhs> core::ops::DivAssign<Rhs> for Ratio<LhsNum,LhsDen> + where + LhsDen:core::ops::MulAssign<Rhs>, +{ + #[inline] + fn div_assign(&mut self,rhs:Rhs){ + self.den*=rhs; + } +} + +macro_rules! impl_ratio_assign_operator { + ($trait:ident, $method:ident) => { + impl<LhsNum,LhsDen,Rhs> core::ops::$trait<Rhs> for Ratio<LhsNum,LhsDen> + where + LhsNum:core::ops::$trait, + LhsDen:Copy, + Rhs:core::ops::Mul<LhsDen,Output=LhsNum>, + { + #[inline] + fn $method(&mut self,rhs:Rhs){ + self.num.$method(rhs*self.den) + } + } + }; +} + +impl_ratio_assign_operator!(AddAssign,add_assign); +impl_ratio_assign_operator!(SubAssign,sub_assign); +impl_ratio_assign_operator!(RemAssign,rem_assign);