diff --git a/src/wrapping.rs b/src/wrapping.rs index 005729d..ae5d1ba 100644 --- a/src/wrapping.rs +++ b/src/wrapping.rs @@ -16,13 +16,13 @@ use crate::{ from_str::ParseFixedError, traits::{Fixed, FixedSigned, ToFixed}, - types::{LeEqU128, LeEqU16, LeEqU32, LeEqU64, LeEqU8}, FixedI128, FixedI16, FixedI32, FixedI64, FixedI8, FixedU128, FixedU16, FixedU32, FixedU64, FixedU8, }; use core::{ fmt::{Display, Formatter, Result as FmtResult}, iter::{Product, Sum}, + mem, ops::{ Add, AddAssign, BitAnd, BitAndAssign, BitOr, BitOrAssign, BitXor, BitXorAssign, Div, DivAssign, Mul, MulAssign, Neg, Not, Rem, RemAssign, Shl, ShlAssign, Shr, ShrAssign, Sub, @@ -209,7 +209,9 @@ impl Wrapping { pub fn round(self) -> Wrapping { Wrapping(self.0.wrapping_round()) } +} +impl Wrapping { /// Wrapping absolute value. Returns the absolute value, wrapping /// on overflow. /// @@ -223,10 +225,7 @@ impl Wrapping { /// assert_eq!(Wrapping(I16F16::from_num(-5)).abs(), Wrapping(I16F16::from_num(5))); /// assert_eq!(Wrapping(I16F16::min_value()).abs(), Wrapping(I16F16::min_value())); /// ``` - pub fn abs(self) -> Wrapping - where - F: FixedSigned, - { + pub fn abs(self) -> Wrapping { Wrapping(self.0.wrapping_abs()) } } @@ -298,48 +297,139 @@ macro_rules! op { }; } -macro_rules! op_rhs { - ( - $wrapping:ident($Rhs:ty), $Op:ident $op:ident, $OpAssign:ident $op_assign:ident - ) => { - impl $Op<$Rhs> for Wrapping { +macro_rules! op_bitwise { + ($Op:ident $op:ident, $OpAssign:ident $op_assign:ident) => { + impl $Op> for Wrapping + where + F: $Op, + { type Output = Wrapping; #[inline] - fn $op(self, other: $Rhs) -> Wrapping { - Wrapping((self.0).$wrapping(other)) + fn $op(self, other: Wrapping) -> Wrapping { + Wrapping((self.0).$op(other.0)) } } - impl<'a, F: Fixed> $Op<$Rhs> for &'a Wrapping { + impl<'a, F> $Op> for &'a Wrapping + where + &'a F: $Op, + { type Output = Wrapping; #[inline] - fn $op(self, other: $Rhs) -> Wrapping { - Wrapping((self.0).$wrapping(other)) + fn $op(self, other: Wrapping) -> Wrapping { + Wrapping((self.0).$op(other.0)) } } - impl<'a, F: Fixed> $Op<&'a $Rhs> for Wrapping { + impl<'a, F> $Op<&'a Wrapping> for Wrapping + where + F: $Op<&'a F, Output = F>, + { type Output = Wrapping; #[inline] - fn $op(self, other: &$Rhs) -> Wrapping { - Wrapping((self.0).$wrapping(*other)) + fn $op(self, other: &'a Wrapping) -> Wrapping { + Wrapping((self.0).$op(&other.0)) } } - impl<'a, 'b, F: Fixed> $Op<&'a $Rhs> for &'b Wrapping { + impl<'a, 'b, F> $Op<&'a Wrapping> for &'b Wrapping + where + &'b F: $Op<&'a F, Output = F>, + { type Output = Wrapping; #[inline] - fn $op(self, other: &$Rhs) -> Wrapping { - Wrapping((self.0).$wrapping(*other)) + fn $op(self, other: &'a Wrapping) -> Wrapping { + Wrapping((self.0).$op(&other.0)) } } - impl $OpAssign<$Rhs> for Wrapping { + impl $OpAssign> for Wrapping + where + F: $OpAssign, + { #[inline] - fn $op_assign(&mut self, other: $Rhs) { - self.0 = (self.0).$wrapping(other); + fn $op_assign(&mut self, other: Wrapping) { + (self.0).$op_assign(other.0); } } - impl<'a, F: Fixed> $OpAssign<&'a $Rhs> for Wrapping { + impl<'a, F> $OpAssign<&'a Wrapping> for Wrapping + where + F: $OpAssign<&'a F>, + { #[inline] - fn $op_assign(&mut self, other: &$Rhs) { - self.0 = (self.0).$wrapping(*other); + fn $op_assign(&mut self, other: &'a Wrapping) { + (self.0).$op_assign(&other.0); + } + } + }; +} + +macro_rules! op_shift { + ($Op:ident $op:ident, $OpAssign:ident $op_assign:ident) => { + impl $Op for Wrapping + where + F: $Op, + { + type Output = Wrapping; + #[allow(clippy::suspicious_op_assign_impl)] + #[inline] + fn $op(self, other: u32) -> Wrapping { + let nbits = mem::size_of::() as u32 * 8; + Wrapping((self.0).$op(other % nbits)) + } + } + impl<'a, F> $Op for &'a Wrapping + where + &'a F: $Op, + { + type Output = Wrapping; + #[allow(clippy::suspicious_op_assign_impl)] + #[inline] + fn $op(self, other: u32) -> Wrapping { + let nbits = mem::size_of::() as u32 * 8; + Wrapping((self.0).$op(other % nbits)) + } + } + impl<'a, F> $Op<&'a u32> for Wrapping + where + F: $Op, + { + type Output = Wrapping; + #[allow(clippy::suspicious_op_assign_impl)] + #[inline] + fn $op(self, other: &u32) -> Wrapping { + let nbits = mem::size_of::() as u32 * 8; + Wrapping((self.0).$op(*other % nbits)) + } + } + impl<'a, 'b, F> $Op<&'a u32> for &'b Wrapping + where + &'b F: $Op, + { + type Output = Wrapping; + #[allow(clippy::suspicious_op_assign_impl)] + #[inline] + fn $op(self, other: &u32) -> Wrapping { + let nbits = mem::size_of::() as u32 * 8; + Wrapping((self.0).$op(*other % nbits)) + } + } + impl $OpAssign for Wrapping + where + F: $OpAssign, + { + #[allow(clippy::suspicious_op_assign_impl)] + #[inline] + fn $op_assign(&mut self, other: u32) { + let nbits = mem::size_of::() as u32 * 8; + (self.0).$op_assign(other % nbits); + } + } + impl<'a, F> $OpAssign<&'a u32> for Wrapping + where + F: $OpAssign, + { + #[allow(clippy::suspicious_op_assign_impl)] + #[inline] + fn $op_assign(&mut self, other: &u32) { + let nbits = mem::size_of::() as u32 * 8; + (self.0).$op_assign(*other % nbits); } } }; @@ -365,26 +455,32 @@ op! { wrapping_sub, Sub sub, SubAssign sub_assign } op! { wrapping_mul, Mul mul, MulAssign mul_assign } op! { wrapping_div, Div div, DivAssign div_assign } -impl Not for Wrapping { +impl Not for Wrapping +where + F: Not, +{ type Output = Wrapping; #[inline] fn not(self) -> Wrapping { Wrapping((self.0).not()) } } -impl<'a, F: Fixed> Not for &'a Wrapping { +impl<'a, F> Not for &'a Wrapping +where + &'a F: Not, +{ type Output = Wrapping; #[inline] fn not(self) -> Wrapping { Wrapping((self.0).not()) } } -op! { bitand, BitAnd bitand, BitAndAssign bitand_assign } -op! { bitor, BitOr bitor, BitOrAssign bitor_assign } -op! { bitxor, BitXor bitxor, BitXorAssign bitxor_assign } +op_bitwise! { BitAnd bitand, BitAndAssign bitand_assign } +op_bitwise! { BitOr bitor, BitOrAssign bitor_assign } +op_bitwise! { BitXor bitxor, BitXorAssign bitxor_assign } -op_rhs! { wrapping_shl(u32), Shl shl, ShlAssign shl_assign } -op_rhs! { wrapping_shr(u32), Shr shr, ShrAssign shr_assign } +op_shift! { Shl shl, ShlAssign shl_assign } +op_shift! { Shr shr, ShrAssign shr_assign } impl Sum> for Wrapping { fn sum(iter: I) -> Wrapping @@ -429,51 +525,61 @@ impl<'a, F: 'a + Fixed> Product<&'a Wrapping> for Wrapping { } // The following cannot be implemented for Wrapping where F: Fixed, -// otherwise there will be a conflicting implementation error, so we -// need to implement on typed direcly. +// otherwise there will be a conflicting implementation error. For +// example we cannot implement both these without triggering E0119: +// +// impl Op for Wrapping { /* ... */ } +// impl<'a, F: Fixed> Op<&'a F::Bits> for Wrapping { /* ... */ } +// +// To work around this, we provide implementations like this: +// +// impl Op for Wrapping> { /* ... */ } +// impl<'a, Frac> Op<&'a i8> for Wrapping> { /* ... */ } +// impl Op for Wrapping> { /* ... */ } +// impl<'a, Frac> Op<&'a i16> for Wrapping> { /* ... */ } +// ... macro_rules! op_bits { ( - $Fixed:ident($LeEqU:ident)::$wrapping:ident, - $Bits:ident, + $Fixed:ident($Bits:ident)::$wrapping:ident, $Op:ident $op:ident, $OpAssign:ident $op_assign:ident ) => { - impl $Op<$Bits> for Wrapping<$Fixed> { + impl $Op<$Bits> for Wrapping<$Fixed> { type Output = Wrapping<$Fixed>; #[inline] fn $op(self, other: $Bits) -> Wrapping<$Fixed> { Wrapping((self.0).$wrapping(other)) } } - impl<'a, Frac: $LeEqU> $Op<$Bits> for &'a Wrapping<$Fixed> { + impl<'a, Frac> $Op<$Bits> for &'a Wrapping<$Fixed> { type Output = Wrapping<$Fixed>; #[inline] fn $op(self, other: $Bits) -> Wrapping<$Fixed> { Wrapping((self.0).$wrapping(other)) } } - impl<'a, Frac: $LeEqU> $Op<&'a $Bits> for Wrapping<$Fixed> { + impl<'a, Frac> $Op<&'a $Bits> for Wrapping<$Fixed> { type Output = Wrapping<$Fixed>; #[inline] fn $op(self, other: &$Bits) -> Wrapping<$Fixed> { Wrapping((self.0).$wrapping(*other)) } } - impl<'a, 'b, Frac: $LeEqU> $Op<&'a $Bits> for &'b Wrapping<$Fixed> { + impl<'a, 'b, Frac> $Op<&'a $Bits> for &'b Wrapping<$Fixed> { type Output = Wrapping<$Fixed>; #[inline] fn $op(self, other: &$Bits) -> Wrapping<$Fixed> { Wrapping((self.0).$wrapping(*other)) } } - impl $OpAssign<$Bits> for Wrapping<$Fixed> { + impl $OpAssign<$Bits> for Wrapping<$Fixed> { #[inline] fn $op_assign(&mut self, other: $Bits) { self.0 = (self.0).$wrapping(other); } } - impl<'a, Frac: $LeEqU> $OpAssign<&'a $Bits> for Wrapping<$Fixed> { + impl<'a, Frac> $OpAssign<&'a $Bits> for Wrapping<$Fixed> { #[inline] fn $op_assign(&mut self, other: &$Bits) { self.0 = (self.0).$wrapping(*other); @@ -483,19 +589,19 @@ macro_rules! op_bits { } macro_rules! ops { - ($Fixed:ident($LeEqU:ident, $Bits:ident)) => { - op_bits! { $Fixed($LeEqU)::wrapping_mul_int, $Bits, Mul mul, MulAssign mul_assign } - op_bits! { $Fixed($LeEqU)::wrapping_div_int, $Bits, Div div, DivAssign div_assign } - op_bits! { $Fixed($LeEqU)::wrapping_rem_int, $Bits, Rem rem, RemAssign rem_assign } + ($Fixed:ident($Bits:ident)) => { + op_bits! { $Fixed($Bits)::wrapping_mul_int, Mul mul, MulAssign mul_assign } + op_bits! { $Fixed($Bits)::wrapping_div_int, Div div, DivAssign div_assign } + op_bits! { $Fixed($Bits)::wrapping_rem_int, Rem rem, RemAssign rem_assign } }; } -ops! { FixedI8(LeEqU8, i8) } -ops! { FixedI16(LeEqU16, i16) } -ops! { FixedI32(LeEqU32, i32) } -ops! { FixedI64(LeEqU64, i64) } -ops! { FixedI128(LeEqU128, i128) } -ops! { FixedU8(LeEqU8, u8) } -ops! { FixedU16(LeEqU16, u16) } -ops! { FixedU32(LeEqU32, u32) } -ops! { FixedU64(LeEqU64, u64) } -ops! { FixedU128(LeEqU128, u128) } +ops! { FixedI8(i8) } +ops! { FixedI16(i16) } +ops! { FixedI32(i32) } +ops! { FixedI64(i64) } +ops! { FixedI128(i128) } +ops! { FixedU8(u8) } +ops! { FixedU16(u16) } +ops! { FixedU32(u32) } +ops! { FixedU64(u64) } +ops! { FixedU128(u128) }