//! [`Uint`] addition operations. use super::Uint; use crate::{Checked, CheckedSub, CtChoice, Limb, Wrapping, Zero}; use core::ops::{Sub, SubAssign}; use subtle::CtOption; impl Uint { /// Computes `a - (b + borrow)`, returning the result along with the new borrow. #[inline(always)] pub const fn sbb(&self, rhs: &Self, mut borrow: Limb) -> (Self, Limb) { let mut limbs = [Limb::ZERO; LIMBS]; let mut i = 0; while i < LIMBS { let (w, b) = self.limbs[i].sbb(rhs.limbs[i], borrow); limbs[i] = w; borrow = b; i += 1; } (Self { limbs }, borrow) } /// Perform saturating subtraction, returning `ZERO` on underflow. pub const fn saturating_sub(&self, rhs: &Self) -> Self { let (res, underflow) = self.sbb(rhs, Limb::ZERO); if underflow.0 == 0 { res } else { Self::ZERO } } /// Perform wrapping subtraction, discarding underflow and wrapping around /// the boundary of the type. pub const fn wrapping_sub(&self, rhs: &Self) -> Self { self.sbb(rhs, Limb::ZERO).0 } /// Perform wrapping subtraction, returning the truthy value as the second element of the tuple /// if an underflow has occurred. pub(crate) const fn conditional_wrapping_sub( &self, rhs: &Self, choice: CtChoice, ) -> (Self, CtChoice) { let actual_rhs = Uint::ct_select(&Uint::ZERO, rhs, choice); let (res, borrow) = self.sbb(&actual_rhs, Limb::ZERO); (res, CtChoice::from_mask(borrow.0)) } } impl CheckedSub<&Uint> for Uint { type Output = Self; fn checked_sub(&self, rhs: &Self) -> CtOption { let (result, underflow) = self.sbb(rhs, Limb::ZERO); CtOption::new(result, underflow.is_zero()) } } impl Sub for Wrapping> { type Output = Self; fn sub(self, rhs: Self) -> Wrapping> { Wrapping(self.0.wrapping_sub(&rhs.0)) } } impl Sub<&Wrapping>> for Wrapping> { type Output = Wrapping>; fn sub(self, rhs: &Wrapping>) -> Wrapping> { Wrapping(self.0.wrapping_sub(&rhs.0)) } } impl Sub>> for &Wrapping> { type Output = Wrapping>; fn sub(self, rhs: Wrapping>) -> Wrapping> { Wrapping(self.0.wrapping_sub(&rhs.0)) } } impl Sub<&Wrapping>> for &Wrapping> { type Output = Wrapping>; fn sub(self, rhs: &Wrapping>) -> Wrapping> { Wrapping(self.0.wrapping_sub(&rhs.0)) } } impl SubAssign for Wrapping> { fn sub_assign(&mut self, other: Self) { *self = *self - other; } } impl SubAssign<&Wrapping>> for Wrapping> { fn sub_assign(&mut self, other: &Self) { *self = *self - other; } } impl Sub for Checked> { type Output = Self; fn sub(self, rhs: Self) -> Checked> { Checked( self.0 .and_then(|lhs| rhs.0.and_then(|rhs| lhs.checked_sub(&rhs))), ) } } impl Sub<&Checked>> for Checked> { type Output = Checked>; fn sub(self, rhs: &Checked>) -> Checked> { Checked( self.0 .and_then(|lhs| rhs.0.and_then(|rhs| lhs.checked_sub(&rhs))), ) } } impl Sub>> for &Checked> { type Output = Checked>; fn sub(self, rhs: Checked>) -> Checked> { Checked( self.0 .and_then(|lhs| rhs.0.and_then(|rhs| lhs.checked_sub(&rhs))), ) } } impl Sub<&Checked>> for &Checked> { type Output = Checked>; fn sub(self, rhs: &Checked>) -> Checked> { Checked( self.0 .and_then(|lhs| rhs.0.and_then(|rhs| lhs.checked_sub(&rhs))), ) } } impl SubAssign for Checked> { fn sub_assign(&mut self, other: Self) { *self = *self - other; } } impl SubAssign<&Checked>> for Checked> { fn sub_assign(&mut self, other: &Self) { *self = *self - other; } } #[cfg(test)] mod tests { use crate::{CheckedSub, Limb, U128}; #[test] fn sbb_no_borrow() { let (res, borrow) = U128::ONE.sbb(&U128::ONE, Limb::ZERO); assert_eq!(res, U128::ZERO); assert_eq!(borrow, Limb::ZERO); } #[test] fn sbb_with_borrow() { let (res, borrow) = U128::ZERO.sbb(&U128::ONE, Limb::ZERO); assert_eq!(res, U128::MAX); assert_eq!(borrow, Limb::MAX); } #[test] fn wrapping_sub_no_borrow() { assert_eq!(U128::ONE.wrapping_sub(&U128::ONE), U128::ZERO); } #[test] fn wrapping_sub_with_borrow() { assert_eq!(U128::ZERO.wrapping_sub(&U128::ONE), U128::MAX); } #[test] fn checked_sub_ok() { let result = U128::ONE.checked_sub(&U128::ONE); assert_eq!(result.unwrap(), U128::ZERO); } #[test] fn checked_sub_overflow() { let result = U128::ZERO.checked_sub(&U128::ONE); assert!(!bool::from(result.is_some())); } }