#[derive(Clone,Copy,Debug,Hash)] pub struct Ratio{ pub num:Num, pub den:Den, } impl Ratio{ #[inline(always)] pub const fn new(num:Num,den:Den)->Self{ Self{num,den} } } /// The actual divide implementation, Div is replaced with a Ratio constructor pub trait Divide{ type Output; fn divide(self,rhs:Rhs)->Self::Output; } impl Ratio where Num:Divide, { #[inline] pub fn divide(self)->>::Output{ self.num.divide(self.den) } } //take care to use the ratio methods to avoid nested ratios impl Ratio{ #[inline] pub fn mul_ratio(self,rhs:Ratio)->Ratio<>::Output,>::Output> where LhsNum:core::ops::Mul, LhsDen:core::ops::Mul, { Ratio::new(self.num*rhs.num,self.den*rhs.den) } #[inline] pub fn div_ratio(self,rhs:Ratio)->Ratio<>::Output,>::Output> where LhsNum:core::ops::Mul, LhsDen:core::ops::Mul, { Ratio::new(self.num*rhs.den,self.den*rhs.num) } } macro_rules! impl_ratio_method { ($trait:ident, $method:ident, $ratio_method:ident) => { impl Ratio{ #[inline] pub fn $ratio_method(self,rhs:Ratio)->Ratio<>::Output,>::Output> where LhsNum:core::ops::Mul, LhsDen:core::ops::Mul, LhsDen:core::ops::Mul, LhsDen:Copy, RhsDen:Copy, LhsCrossMul:core::ops::$trait, { 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 core::ops::Mul> for Lhs where Lhs:core::ops::Mul, { type Output=Ratio<>::Output,RhsDen>; #[inline] fn mul(self,rhs:Ratio)->Self::Output{ Ratio::new(self*rhs.num,rhs.den) } } */ //operators impl core::ops::Neg for Ratio where LhsNum:core::ops::Neg, { type Output=Ratio<::Output,LhsDen>; #[inline] fn neg(self)->Self::Output{ Ratio::new(-self.num,self.den) } } impl core::ops::Mul for Ratio where LhsNum:core::ops::Mul, { type Output=Ratio<>::Output,LhsDen>; #[inline] fn mul(self,rhs:Rhs)->Self::Output{ Ratio::new(self.num*rhs,self.den) } } impl core::ops::Div for Ratio where LhsDen:core::ops::Mul, { type Output=Ratio>::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 core::ops::$trait for Ratio where LhsNum:core::ops::$trait, LhsDen:Copy, Rhs:core::ops::Mul, { type Output=Ratio<>::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 core::ops::MulAssign for Ratio where LhsNum:core::ops::MulAssign, { #[inline] fn mul_assign(&mut self,rhs:Rhs){ self.num*=rhs; } } impl core::ops::DivAssign for Ratio where LhsDen:core::ops::MulAssign, { #[inline] fn div_assign(&mut self,rhs:Rhs){ self.den*=rhs; } } macro_rules! impl_ratio_assign_operator { ($trait:ident, $method:ident) => { impl core::ops::$trait for Ratio where LhsNum:core::ops::$trait, LhsDen:Copy, Rhs:core::ops::Mul, { #[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);