diff --git a/src/uint/boxed/sub.rs b/src/uint/boxed/sub.rs index 64537a49..34622737 100644 --- a/src/uint/boxed/sub.rs +++ b/src/uint/boxed/sub.rs @@ -1,6 +1,6 @@ //! [`BoxedUint`] subtraction operations. -use crate::{BoxedUint, CheckedSub, Limb, Wrapping, WrappingSub, Zero}; +use crate::{BoxedUint, CheckedSub, Limb, Uint, Wrapping, WrappingSub, Zero, U128, U64}; use core::ops::{Sub, SubAssign}; use subtle::{Choice, ConditionallySelectable, CtOption}; @@ -15,11 +15,11 @@ impl BoxedUint { /// /// Panics if `rhs` has a larger precision than `self`. #[inline(always)] - pub fn sbb_assign(&mut self, rhs: &Self, mut borrow: Limb) -> Limb { - debug_assert!(self.bits_precision() <= rhs.bits_precision()); + pub fn sbb_assign(&mut self, rhs: impl AsRef<[Limb]>, mut borrow: Limb) -> Limb { + debug_assert!(self.bits_precision() <= (rhs.as_ref().len() as u32 * Limb::BITS)); for i in 0..self.nlimbs() { - let (limb, b) = self.limbs[i].sbb(*rhs.limbs.get(i).unwrap_or(&Limb::ZERO), borrow); + let (limb, b) = self.limbs[i].sbb(*rhs.as_ref().get(i).unwrap_or(&Limb::ZERO), borrow); self.limbs[i] = limb; borrow = b; } @@ -82,6 +82,52 @@ impl Sub<&BoxedUint> for &BoxedUint { } } +impl Sub> for BoxedUint { + type Output = BoxedUint; + + fn sub(self, rhs: Uint) -> BoxedUint { + self.sub(&rhs) + } +} + +impl Sub<&Uint> for BoxedUint { + type Output = BoxedUint; + + fn sub(mut self, rhs: &Uint) -> BoxedUint { + self -= rhs; + self + } +} + +impl Sub> for &BoxedUint { + type Output = BoxedUint; + + fn sub(self, rhs: Uint) -> BoxedUint { + self.clone().sub(rhs) + } +} + +impl Sub<&Uint> for &BoxedUint { + type Output = BoxedUint; + + fn sub(self, rhs: &Uint) -> BoxedUint { + self.clone().sub(rhs) + } +} + +impl SubAssign> for BoxedUint { + fn sub_assign(&mut self, rhs: Uint) { + *self -= &rhs; + } +} + +impl SubAssign<&Uint> for BoxedUint { + fn sub_assign(&mut self, rhs: &Uint) { + let carry = self.sbb_assign(rhs.as_limbs(), Limb::ZERO); + assert_eq!(carry.0, 0, "attempted to sub with overflow"); + } +} + impl SubAssign> for Wrapping { fn sub_assign(&mut self, other: Wrapping) { self.0.sbb_assign(&other.0, Limb::ZERO); @@ -100,6 +146,62 @@ impl WrappingSub for BoxedUint { } } +macro_rules! impl_sub_primitive { + ($($primitive:ty),+) => { + $( + impl Sub<$primitive> for BoxedUint { + type Output = BoxedUint; + + #[inline] + fn sub(self, rhs: $primitive) -> BoxedUint { + self - U64::from(rhs) + } + } + + impl Sub<$primitive> for &BoxedUint { + type Output = BoxedUint; + + #[inline] + fn sub(self, rhs: $primitive) -> BoxedUint { + self - U64::from(rhs) + } + } + + impl SubAssign<$primitive> for BoxedUint { + fn sub_assign(&mut self, rhs: $primitive) { + *self -= U64::from(rhs); + } + } + )+ + }; +} + +impl_sub_primitive!(u8, u16, u32, u64); + +impl Sub for BoxedUint { + type Output = BoxedUint; + + #[inline] + fn sub(self, rhs: u128) -> BoxedUint { + self - U128::from(rhs) + } +} + +impl Sub for &BoxedUint { + type Output = BoxedUint; + + #[inline] + fn sub(self, rhs: u128) -> BoxedUint { + self - U128::from(rhs) + } +} + +impl SubAssign for BoxedUint { + fn sub_assign(&mut self, rhs: u128) { + *self -= U128::from(rhs); + } +} + #[cfg(test)] #[allow(clippy::unwrap_used)] mod tests { @@ -123,6 +225,13 @@ mod tests { assert_eq!(borrow, Limb::MAX); } + #[test] + fn sub_with_u32_rhs() { + let a = BoxedUint::from(0x100000000u64); + let b = a - u32::MAX; + assert_eq!(b, BoxedUint::one()); + } + #[test] fn checked_sub_ok() { let result = BoxedUint::one().checked_sub(&BoxedUint::one());