Add Sub/AddAssign impl for NumOpResult<Amount/SignedAmount>
What changed, and why it matters
This commit adds convenience operators (+= and -=) for a special result wrapper around Bitcoin amount types. It does not change how amounts are validated or how overflow is handled; it only lets programmers write `res += amount` instead of `res = res + amount`. There is no security bug visible in the change.
No security action required. This is a routine API ergonomics enhancement. Reviewers may optionally verify that the macro-generated implementations exactly match the existing `NumOpResult` generic `AddAssign`/`SubAssign` semantics, which the included tests appear to cover.
Security signals we found
No unsafe code introduced
No validation logic changed; arithmetic bounds checks remain in the pre-existing Add/Sub implementations
Error propagation is explicit and tested
No new dependencies or I/O
No mention of security, CVE, or vulnerability in commit message or diff
Evidence from the diff
The patch introduces impl_add_assign_for_results! and impl_sub_assign_for_results! macros and invokes them for Amount and SignedAmount wrapped in NumOpResult. The implementations mirror the existing fallible Add/Sub behavior: a valid left-hand side combined with a valid right-hand side delegates to the existing +/- operators that already return NumOpResult; any error state is preserved and tagged with the current operation. API snapshot files are updated to reflect the new trait implementations. Unit tests cover valid, error, and mixed error cases.
Changed components
units/src/amount/result.rsunits/src/internal_macros.rsapi/units/all-features.txtapi/units/alloc-only.txtapi/units/no-features.txtInspect captured patch +171 / −1
diff --git a/api/units/all-features.txt b/api/units/all-features.txt
index cd908025..50fc84ca 100644
--- a/api/units/all-features.txt
+++ b/api/units/all-features.txt
@@ -892,10 +892,14 @@ impl core::ops::arith::AddAssign for bitcoin_units::FeeRate
impl core::ops::arith::AddAssign for bitcoin_units::Weight
impl core::ops::arith::AddAssign for bitcoin_units::block::BlockHeightInterval
impl core::ops::arith::AddAssign for bitcoin_units::block::BlockMtpInterval
+impl core::ops::arith::AddAssign for bitcoin_units::result::NumOpResult<bitcoin_units::Amount>
+impl core::ops::arith::AddAssign for bitcoin_units::result::NumOpResult<bitcoin_units::SignedAmount>
impl core::ops::arith::AddAssign<&bitcoin_units::FeeRate> for bitcoin_units::FeeRate
impl core::ops::arith::AddAssign<&bitcoin_units::Weight> for bitcoin_units::Weight
impl core::ops::arith::AddAssign<&bitcoin_units::block::BlockHeightInterval> for bitcoin_units::block::BlockHeightInterval
impl core::ops::arith::AddAssign<&bitcoin_units::block::BlockMtpInterval> for bitcoin_units::block::BlockMtpInterval
+impl core::ops::arith::AddAssign<bitcoin_units::Amount> for bitcoin_units::result::NumOpResult<bitcoin_units::Amount>
+impl core::ops::arith::AddAssign<bitcoin_units::SignedAmount> for bitcoin_units::result::NumOpResult<bitcoin_units::SignedAmount>
impl core::ops::arith::Div for bitcoin_units::Amount
impl core::ops::arith::Div for bitcoin_units::SignedAmount
impl core::ops::arith::Div for bitcoin_units::Weight
@@ -1080,10 +1084,14 @@ impl core::ops::arith::SubAssign for bitcoin_units::FeeRate
impl core::ops::arith::SubAssign for bitcoin_units::Weight
impl core::ops::arith::SubAssign for bitcoin_units::block::BlockHeightInterval
impl core::ops::arith::SubAssign for bitcoin_units::block::BlockMtpInterval
+impl core::ops::arith::SubAssign for bitcoin_units::result::NumOpResult<bitcoin_units::Amount>
+impl core::ops::arith::SubAssign for bitcoin_units::result::NumOpResult<bitcoin_units::SignedAmount>
impl core::ops::arith::SubAssign<&bitcoin_units::FeeRate> for bitcoin_units::FeeRate
impl core::ops::arith::SubAssign<&bitcoin_units::Weight> for bitcoin_units::Weight
impl core::ops::arith::SubAssign<&bitcoin_units::block::BlockHeightInterval> for bitcoin_units::block::BlockHeightInterval
impl core::ops::arith::SubAssign<&bitcoin_units::block::BlockMtpInterval> for bitcoin_units::block::BlockMtpInterval
+impl core::ops::arith::SubAssign<bitcoin_units::Amount> for bitcoin_units::result::NumOpResult<bitcoin_units::Amount>
+impl core::ops::arith::SubAssign<bitcoin_units::SignedAmount> for bitcoin_units::result::NumOpResult<bitcoin_units::SignedAmount>
impl core::panic::unwind_safe::RefUnwindSafe for bitcoin_units::Amount
impl core::panic::unwind_safe::RefUnwindSafe for bitcoin_units::BlockTime
impl core::panic::unwind_safe::RefUnwindSafe for bitcoin_units::FeeRate
@@ -2382,6 +2390,8 @@ pub fn bitcoin_units::result::NumOpResult<T>::unwrap(self) -> T
pub fn bitcoin_units::result::NumOpResult<T>::unwrap_err(self) -> bitcoin_units::result::NumOpError
pub fn bitcoin_units::result::NumOpResult<T>::unwrap_or(self, default: T) -> T
pub fn bitcoin_units::result::NumOpResult<T>::unwrap_or_else<F>(self, f: F) -> T where F: core::ops::function::FnOnce() -> T
+pub fn bitcoin_units::result::NumOpResult<bitcoin_units::Amount>::add_assign(&mut self, rhs: Self)
+pub fn bitcoin_units::result::NumOpResult<bitcoin_units::Amount>::add_assign(&mut self, rhs: bitcoin_units::Amount)
pub fn bitcoin_units::result::NumOpResult<bitcoin_units::Amount>::div(self, rhs: &bitcoin_units::FeeRate) -> Self::Output
pub fn bitcoin_units::result::NumOpResult<bitcoin_units::Amount>::div(self, rhs: &bitcoin_units::Weight) -> Self::Output
pub fn bitcoin_units::result::NumOpResult<bitcoin_units::Amount>::div(self, rhs: &bitcoin_units::result::NumOpResult<bitcoin_units::FeeRate>) -> Self::Output
@@ -2402,12 +2412,16 @@ pub fn bitcoin_units::result::NumOpResult<bitcoin_units::Amount>::mul_assign(&mu
pub fn bitcoin_units::result::NumOpResult<bitcoin_units::Amount>::mul_assign(&mut self, rhs: u64)
pub fn bitcoin_units::result::NumOpResult<bitcoin_units::Amount>::rem(self, modulus: u64) -> Self::Output
pub fn bitcoin_units::result::NumOpResult<bitcoin_units::Amount>::rem(self, rhs: &u64) -> Self::Output
+pub fn bitcoin_units::result::NumOpResult<bitcoin_units::Amount>::sub_assign(&mut self, rhs: Self)
+pub fn bitcoin_units::result::NumOpResult<bitcoin_units::Amount>::sub_assign(&mut self, rhs: bitcoin_units::Amount)
pub fn bitcoin_units::result::NumOpResult<bitcoin_units::Amount>::sum<I>(iter: I) -> Self where I: core::iter::traits::iterator::Iterator<Item = &'a Self>
pub fn bitcoin_units::result::NumOpResult<bitcoin_units::Amount>::sum<I>(iter: I) -> Self where I: core::iter::traits::iterator::Iterator<Item = Self>
pub fn bitcoin_units::result::NumOpResult<bitcoin_units::FeeRate>::mul(self, rhs: &bitcoin_units::Weight) -> Self::Output
pub fn bitcoin_units::result::NumOpResult<bitcoin_units::FeeRate>::mul(self, rhs: &bitcoin_units::result::NumOpResult<bitcoin_units::Weight>) -> Self::Output
pub fn bitcoin_units::result::NumOpResult<bitcoin_units::FeeRate>::mul(self, rhs: bitcoin_units::Weight) -> Self::Output
pub fn bitcoin_units::result::NumOpResult<bitcoin_units::FeeRate>::mul(self, rhs: bitcoin_units::result::NumOpResult<bitcoin_units::Weight>) -> Self::Output
+pub fn bitcoin_units::result::NumOpResult<bitcoin_units::SignedAmount>::add_assign(&mut self, rhs: Self)
+pub fn bitcoin_units::result::NumOpResult<bitcoin_units::SignedAmount>::add_assign(&mut self, rhs: bitcoin_units::SignedAmount)
pub fn bitcoin_units::result::NumOpResult<bitcoin_units::SignedAmount>::div(self, rhs: &i64) -> Self::Output
pub fn bitcoin_units::result::NumOpResult<bitcoin_units::SignedAmount>::div(self, rhs: i64) -> Self::Output
pub fn bitcoin_units::result::NumOpResult<bitcoin_units::SignedAmount>::div_assign(&mut self, rhs: &i64)
@@ -2420,6 +2434,8 @@ pub fn bitcoin_units::result::NumOpResult<bitcoin_units::SignedAmount>::mul_assi
pub fn bitcoin_units::result::NumOpResult<bitcoin_units::SignedAmount>::mul_assign(&mut self, rhs: i64)
pub fn bitcoin_units::result::NumOpResult<bitcoin_units::SignedAmount>::rem(self, modulus: i64) -> Self::Output
pub fn bitcoin_units::result::NumOpResult<bitcoin_units::SignedAmount>::rem(self, rhs: &i64) -> Self::Output
+pub fn bitcoin_units::result::NumOpResult<bitcoin_units::SignedAmount>::sub_assign(&mut self, rhs: Self)
+pub fn bitcoin_units::result::NumOpResult<bitcoin_units::SignedAmount>::sub_assign(&mut self, rhs: bitcoin_units::SignedAmount)
pub fn bitcoin_units::result::NumOpResult<bitcoin_units::SignedAmount>::sum<I>(iter: I) -> Self where I: core::iter::traits::iterator::Iterator<Item = &'a Self>
pub fn bitcoin_units::result::NumOpResult<bitcoin_units::SignedAmount>::sum<I>(iter: I) -> Self where I: core::iter::traits::iterator::Iterator<Item = Self>
pub fn bitcoin_units::result::NumOpResult<bitcoin_units::Weight>::mul(self, rhs: &bitcoin_units::FeeRate) -> Self::Output
diff --git a/api/units/alloc-only.txt b/api/units/alloc-only.txt
index b6333f98..eeb4cec3 100644
--- a/api/units/alloc-only.txt
+++ b/api/units/alloc-only.txt
@@ -721,10 +721,14 @@ impl core::ops::arith::AddAssign for bitcoin_units::FeeRate
impl core::ops::arith::AddAssign for bitcoin_units::Weight
impl core::ops::arith::AddAssign for bitcoin_units::block::BlockHeightInterval
impl core::ops::arith::AddAssign for bitcoin_units::block::BlockMtpInterval
+impl core::ops::arith::AddAssign for bitcoin_units::result::NumOpResult<bitcoin_units::Amount>
+impl core::ops::arith::AddAssign for bitcoin_units::result::NumOpResult<bitcoin_units::SignedAmount>
impl core::ops::arith::AddAssign<&bitcoin_units::FeeRate> for bitcoin_units::FeeRate
impl core::ops::arith::AddAssign<&bitcoin_units::Weight> for bitcoin_units::Weight
impl core::ops::arith::AddAssign<&bitcoin_units::block::BlockHeightInterval> for bitcoin_units::block::BlockHeightInterval
impl core::ops::arith::AddAssign<&bitcoin_units::block::BlockMtpInterval> for bitcoin_units::block::BlockMtpInterval
+impl core::ops::arith::AddAssign<bitcoin_units::Amount> for bitcoin_units::result::NumOpResult<bitcoin_units::Amount>
+impl core::ops::arith::AddAssign<bitcoin_units::SignedAmount> for bitcoin_units::result::NumOpResult<bitcoin_units::SignedAmount>
impl core::ops::arith::Div for bitcoin_units::Amount
impl core::ops::arith::Div for bitcoin_units::SignedAmount
impl core::ops::arith::Div for bitcoin_units::Weight
@@ -909,10 +913,14 @@ impl core::ops::arith::SubAssign for bitcoin_units::FeeRate
impl core::ops::arith::SubAssign for bitcoin_units::Weight
impl core::ops::arith::SubAssign for bitcoin_units::block::BlockHeightInterval
impl core::ops::arith::SubAssign for bitcoin_units::block::BlockMtpInterval
+impl core::ops::arith::SubAssign for bitcoin_units::result::NumOpResult<bitcoin_units::Amount>
+impl core::ops::arith::SubAssign for bitcoin_units::result::NumOpResult<bitcoin_units::SignedAmount>
impl core::ops::arith::SubAssign<&bitcoin_units::FeeRate> for bitcoin_units::FeeRate
impl core::ops::arith::SubAssign<&bitcoin_units::Weight> for bitcoin_units::Weight
impl core::ops::arith::SubAssign<&bitcoin_units::block::BlockHeightInterval> for bitcoin_units::block::BlockHeightInterval
impl core::ops::arith::SubAssign<&bitcoin_units::block::BlockMtpInterval> for bitcoin_units::block::BlockMtpInterval
+impl core::ops::arith::SubAssign<bitcoin_units::Amount> for bitcoin_units::result::NumOpResult<bitcoin_units::Amount>
+impl core::ops::arith::SubAssign<bitcoin_units::SignedAmount> for bitcoin_units::result::NumOpResult<bitcoin_units::SignedAmount>
impl core::panic::unwind_safe::RefUnwindSafe for bitcoin_units::Amount
impl core::panic::unwind_safe::RefUnwindSafe for bitcoin_units::BlockTime
impl core::panic::unwind_safe::RefUnwindSafe for bitcoin_units::FeeRate
@@ -2022,6 +2030,8 @@ pub fn bitcoin_units::result::NumOpResult<T>::unwrap(self) -> T
pub fn bitcoin_units::result::NumOpResult<T>::unwrap_err(self) -> bitcoin_units::result::NumOpError
pub fn bitcoin_units::result::NumOpResult<T>::unwrap_or(self, default: T) -> T
pub fn bitcoin_units::result::NumOpResult<T>::unwrap_or_else<F>(self, f: F) -> T where F: core::ops::function::FnOnce() -> T
+pub fn bitcoin_units::result::NumOpResult<bitcoin_units::Amount>::add_assign(&mut self, rhs: Self)
+pub fn bitcoin_units::result::NumOpResult<bitcoin_units::Amount>::add_assign(&mut self, rhs: bitcoin_units::Amount)
pub fn bitcoin_units::result::NumOpResult<bitcoin_units::Amount>::div(self, rhs: &bitcoin_units::FeeRate) -> Self::Output
pub fn bitcoin_units::result::NumOpResult<bitcoin_units::Amount>::div(self, rhs: &bitcoin_units::Weight) -> Self::Output
pub fn bitcoin_units::result::NumOpResult<bitcoin_units::Amount>::div(self, rhs: &bitcoin_units::result::NumOpResult<bitcoin_units::FeeRate>) -> Self::Output
@@ -2042,12 +2052,16 @@ pub fn bitcoin_units::result::NumOpResult<bitcoin_units::Amount>::mul_assign(&mu
pub fn bitcoin_units::result::NumOpResult<bitcoin_units::Amount>::mul_assign(&mut self, rhs: u64)
pub fn bitcoin_units::result::NumOpResult<bitcoin_units::Amount>::rem(self, modulus: u64) -> Self::Output
pub fn bitcoin_units::result::NumOpResult<bitcoin_units::Amount>::rem(self, rhs: &u64) -> Self::Output
+pub fn bitcoin_units::result::NumOpResult<bitcoin_units::Amount>::sub_assign(&mut self, rhs: Self)
+pub fn bitcoin_units::result::NumOpResult<bitcoin_units::Amount>::sub_assign(&mut self, rhs: bitcoin_units::Amount)
pub fn bitcoin_units::result::NumOpResult<bitcoin_units::Amount>::sum<I>(iter: I) -> Self where I: core::iter::traits::iterator::Iterator<Item = &'a Self>
pub fn bitcoin_units::result::NumOpResult<bitcoin_units::Amount>::sum<I>(iter: I) -> Self where I: core::iter::traits::iterator::Iterator<Item = Self>
pub fn bitcoin_units::result::NumOpResult<bitcoin_units::FeeRate>::mul(self, rhs: &bitcoin_units::Weight) -> Self::Output
pub fn bitcoin_units::result::NumOpResult<bitcoin_units::FeeRate>::mul(self, rhs: &bitcoin_units::result::NumOpResult<bitcoin_units::Weight>) -> Self::Output
pub fn bitcoin_units::result::NumOpResult<bitcoin_units::FeeRate>::mul(self, rhs: bitcoin_units::Weight) -> Self::Output
pub fn bitcoin_units::result::NumOpResult<bitcoin_units::FeeRate>::mul(self, rhs: bitcoin_units::result::NumOpResult<bitcoin_units::Weight>) -> Self::Output
+pub fn bitcoin_units::result::NumOpResult<bitcoin_units::SignedAmount>::add_assign(&mut self, rhs: Self)
+pub fn bitcoin_units::result::NumOpResult<bitcoin_units::SignedAmount>::add_assign(&mut self, rhs: bitcoin_units::SignedAmount)
pub fn bitcoin_units::result::NumOpResult<bitcoin_units::SignedAmount>::div(self, rhs: &i64) -> Self::Output
pub fn bitcoin_units::result::NumOpResult<bitcoin_units::SignedAmount>::div(self, rhs: i64) -> Self::Output
pub fn bitcoin_units::result::NumOpResult<bitcoin_units::SignedAmount>::div_assign(&mut self, rhs: &i64)
@@ -2060,6 +2074,8 @@ pub fn bitcoin_units::result::NumOpResult<bitcoin_units::SignedAmount>::mul_assi
pub fn bitcoin_units::result::NumOpResult<bitcoin_units::SignedAmount>::mul_assign(&mut self, rhs: i64)
pub fn bitcoin_units::result::NumOpResult<bitcoin_units::SignedAmount>::rem(self, modulus: i64) -> Self::Output
pub fn bitcoin_units::result::NumOpResult<bitcoin_units::SignedAmount>::rem(self, rhs: &i64) -> Self::Output
+pub fn bitcoin_units::result::NumOpResult<bitcoin_units::SignedAmount>::sub_assign(&mut self, rhs: Self)
+pub fn bitcoin_units::result::NumOpResult<bitcoin_units::SignedAmount>::sub_assign(&mut self, rhs: bitcoin_units::SignedAmount)
pub fn bitcoin_units::result::NumOpResult<bitcoin_units::SignedAmount>::sum<I>(iter: I) -> Self where I: core::iter::traits::iterator::Iterator<Item = &'a Self>
pub fn bitcoin_units::result::NumOpResult<bitcoin_units::SignedAmount>::sum<I>(iter: I) -> Self where I: core::iter::traits::iterator::Iterator<Item = Self>
pub fn bitcoin_units::result::NumOpResult<bitcoin_units::Weight>::mul(self, rhs: &bitcoin_units::FeeRate) -> Self::Output
diff --git a/api/units/no-features.txt b/api/units/no-features.txt
index 4dbb5000..8c0c21e5 100644
--- a/api/units/no-features.txt
+++ b/api/units/no-features.txt
@@ -698,10 +698,14 @@ impl core::ops::arith::AddAssign for bitcoin_units::FeeRate
impl core::ops::arith::AddAssign for bitcoin_units::Weight
impl core::ops::arith::AddAssign for bitcoin_units::block::BlockHeightInterval
impl core::ops::arith::AddAssign for bitcoin_units::block::BlockMtpInterval
+impl core::ops::arith::AddAssign for bitcoin_units::result::NumOpResult<bitcoin_units::Amount>
+impl core::ops::arith::AddAssign for bitcoin_units::result::NumOpResult<bitcoin_units::SignedAmount>
impl core::ops::arith::AddAssign<&bitcoin_units::FeeRate> for bitcoin_units::FeeRate
impl core::ops::arith::AddAssign<&bitcoin_units::Weight> for bitcoin_units::Weight
impl core::ops::arith::AddAssign<&bitcoin_units::block::BlockHeightInterval> for bitcoin_units::block::BlockHeightInterval
impl core::ops::arith::AddAssign<&bitcoin_units::block::BlockMtpInterval> for bitcoin_units::block::BlockMtpInterval
+impl core::ops::arith::AddAssign<bitcoin_units::Amount> for bitcoin_units::result::NumOpResult<bitcoin_units::Amount>
+impl core::ops::arith::AddAssign<bitcoin_units::SignedAmount> for bitcoin_units::result::NumOpResult<bitcoin_units::SignedAmount>
impl core::ops::arith::Div for bitcoin_units::Amount
impl core::ops::arith::Div for bitcoin_units::SignedAmount
impl core::ops::arith::Div for bitcoin_units::Weight
@@ -886,10 +890,14 @@ impl core::ops::arith::SubAssign for bitcoin_units::FeeRate
impl core::ops::arith::SubAssign for bitcoin_units::Weight
impl core::ops::arith::SubAssign for bitcoin_units::block::BlockHeightInterval
impl core::ops::arith::SubAssign for bitcoin_units::block::BlockMtpInterval
+impl core::ops::arith::SubAssign for bitcoin_units::result::NumOpResult<bitcoin_units::Amount>
+impl core::ops::arith::SubAssign for bitcoin_units::result::NumOpResult<bitcoin_units::SignedAmount>
impl core::ops::arith::SubAssign<&bitcoin_units::FeeRate> for bitcoin_units::FeeRate
impl core::ops::arith::SubAssign<&bitcoin_units::Weight> for bitcoin_units::Weight
impl core::ops::arith::SubAssign<&bitcoin_units::block::BlockHeightInterval> for bitcoin_units::block::BlockHeightInterval
impl core::ops::arith::SubAssign<&bitcoin_units::block::BlockMtpInterval> for bitcoin_units::block::BlockMtpInterval
+impl core::ops::arith::SubAssign<bitcoin_units::Amount> for bitcoin_units::result::NumOpResult<bitcoin_units::Amount>
+impl core::ops::arith::SubAssign<bitcoin_units::SignedAmount> for bitcoin_units::result::NumOpResult<bitcoin_units::SignedAmount>
impl core::panic::unwind_safe::RefUnwindSafe for bitcoin_units::Amount
impl core::panic::unwind_safe::RefUnwindSafe for bitcoin_units::BlockTime
impl core::panic::unwind_safe::RefUnwindSafe for bitcoin_units::FeeRate
@@ -1964,6 +1972,8 @@ pub fn bitcoin_units::result::NumOpResult<T>::unwrap(self) -> T
pub fn bitcoin_units::result::NumOpResult<T>::unwrap_err(self) -> bitcoin_units::result::NumOpError
pub fn bitcoin_units::result::NumOpResult<T>::unwrap_or(self, default: T) -> T
pub fn bitcoin_units::result::NumOpResult<T>::unwrap_or_else<F>(self, f: F) -> T where F: core::ops::function::FnOnce() -> T
+pub fn bitcoin_units::result::NumOpResult<bitcoin_units::Amount>::add_assign(&mut self, rhs: Self)
+pub fn bitcoin_units::result::NumOpResult<bitcoin_units::Amount>::add_assign(&mut self, rhs: bitcoin_units::Amount)
pub fn bitcoin_units::result::NumOpResult<bitcoin_units::Amount>::div(self, rhs: &bitcoin_units::FeeRate) -> Self::Output
pub fn bitcoin_units::result::NumOpResult<bitcoin_units::Amount>::div(self, rhs: &bitcoin_units::Weight) -> Self::Output
pub fn bitcoin_units::result::NumOpResult<bitcoin_units::Amount>::div(self, rhs: &bitcoin_units::result::NumOpResult<bitcoin_units::FeeRate>) -> Self::Output
@@ -1984,12 +1994,16 @@ pub fn bitcoin_units::result::NumOpResult<bitcoin_units::Amount>::mul_assign(&mu
pub fn bitcoin_units::result::NumOpResult<bitcoin_units::Amount>::mul_assign(&mut self, rhs: u64)
pub fn bitcoin_units::result::NumOpResult<bitcoin_units::Amount>::rem(self, modulus: u64) -> Self::Output
pub fn bitcoin_units::result::NumOpResult<bitcoin_units::Amount>::rem(self, rhs: &u64) -> Self::Output
+pub fn bitcoin_units::result::NumOpResult<bitcoin_units::Amount>::sub_assign(&mut self, rhs: Self)
+pub fn bitcoin_units::result::NumOpResult<bitcoin_units::Amount>::sub_assign(&mut self, rhs: bitcoin_units::Amount)
pub fn bitcoin_units::result::NumOpResult<bitcoin_units::Amount>::sum<I>(iter: I) -> Self where I: core::iter::traits::iterator::Iterator<Item = &'a Self>
pub fn bitcoin_units::result::NumOpResult<bitcoin_units::Amount>::sum<I>(iter: I) -> Self where I: core::iter::traits::iterator::Iterator<Item = Self>
pub fn bitcoin_units::result::NumOpResult<bitcoin_units::FeeRate>::mul(self, rhs: &bitcoin_units::Weight) -> Self::Output
pub fn bitcoin_units::result::NumOpResult<bitcoin_units::FeeRate>::mul(self, rhs: &bitcoin_units::result::NumOpResult<bitcoin_units::Weight>) -> Self::Output
pub fn bitcoin_units::result::NumOpResult<bitcoin_units::FeeRate>::mul(self, rhs: bitcoin_units::Weight) -> Self::Output
pub fn bitcoin_units::result::NumOpResult<bitcoin_units::FeeRate>::mul(self, rhs: bitcoin_units::result::NumOpResult<bitcoin_units::Weight>) -> Self::Output
+pub fn bitcoin_units::result::NumOpResult<bitcoin_units::SignedAmount>::add_assign(&mut self, rhs: Self)
+pub fn bitcoin_units::result::NumOpResult<bitcoin_units::SignedAmount>::add_assign(&mut self, rhs: bitcoin_units::SignedAmount)
pub fn bitcoin_units::result::NumOpResult<bitcoin_units::SignedAmount>::div(self, rhs: &i64) -> Self::Output
pub fn bitcoin_units::result::NumOpResult<bitcoin_units::SignedAmount>::div(self, rhs: i64) -> Self::Output
pub fn bitcoin_units::result::NumOpResult<bitcoin_units::SignedAmount>::div_assign(&mut self, rhs: &i64)
@@ -2002,6 +2016,8 @@ pub fn bitcoin_units::result::NumOpResult<bitcoin_units::SignedAmount>::mul_assi
pub fn bitcoin_units::result::NumOpResult<bitcoin_units::SignedAmount>::mul_assign(&mut self, rhs: i64)
pub fn bitcoin_units::result::NumOpResult<bitcoin_units::SignedAmount>::rem(self, modulus: i64) -> Self::Output
pub fn bitcoin_units::result::NumOpResult<bitcoin_units::SignedAmount>::rem(self, rhs: &i64) -> Self::Output
+pub fn bitcoin_units::result::NumOpResult<bitcoin_units::SignedAmount>::sub_assign(&mut self, rhs: Self)
+pub fn bitcoin_units::result::NumOpResult<bitcoin_units::SignedAmount>::sub_assign(&mut self, rhs: bitcoin_units::SignedAmount)
pub fn bitcoin_units::result::NumOpResult<bitcoin_units::SignedAmount>::sum<I>(iter: I) -> Self where I: core::iter::traits::iterator::Iterator<Item = &'a Self>
pub fn bitcoin_units::result::NumOpResult<bitcoin_units::SignedAmount>::sum<I>(iter: I) -> Self where I: core::iter::traits::iterator::Iterator<Item = Self>
pub fn bitcoin_units::result::NumOpResult<bitcoin_units::Weight>::mul(self, rhs: &bitcoin_units::FeeRate) -> Self::Output
diff --git a/units/src/amount/result.rs b/units/src/amount/result.rs
index 2f940fe4..ac2ac818 100644
--- a/units/src/amount/result.rs
+++ b/units/src/amount/result.rs
@@ -8,7 +8,7 @@ use core::ops;
use NumOpResult as R;
use super::{Amount, SignedAmount};
-use crate::internal_macros::{impl_div_assign, impl_mul_assign};
+use crate::internal_macros::{impl_add_assign_for_results, impl_sub_assign_for_results, impl_div_assign, impl_mul_assign};
use crate::result::{MathOp, NumOpError, NumOpResult, OptionExt};
impl From<Amount> for NumOpResult<Amount> {
@@ -194,6 +194,11 @@ impl_mul_assign!(NumOpResult<SignedAmount>, i64);
impl_div_assign!(NumOpResult<Amount>, u64);
impl_div_assign!(NumOpResult<SignedAmount>, i64);
+impl_add_assign_for_results!(Amount);
+impl_add_assign_for_results!(SignedAmount);
+impl_sub_assign_for_results!(Amount);
+impl_sub_assign_for_results!(SignedAmount);
+
impl ops::Neg for SignedAmount {
type Output = Self;
@@ -322,4 +327,67 @@ mod tests {
let sum: NumOpResult<SignedAmount> = amounts.into_iter().sum();
assert!(matches!(sum, NumOpResult::Error(_)));
}
+
+ #[test]
+ fn test_op_assign_amount() {
+ let sat = Amount::from_sat_u32(50);
+
+ let mut res = sat + sat;
+ res += Amount::from_sat_u32(50);
+ assert_eq!(res, NumOpResult::Valid(Amount::from_sat_u32(150)));
+
+ let add_err = NumOpResult::Error(NumOpError::while_doing(MathOp::Add));
+ res += add_err; // Add an error result
+ assert_eq!(res, add_err);
+
+ let mut res = sat + sat;
+ res -= Amount::from_sat_u32(20);
+ assert_eq!(res, NumOpResult::Valid(Amount::from_sat_u32(80)));
+
+ let sub_err = NumOpResult::Error(NumOpError::while_doing(MathOp::Sub));
+ res -= sub_err; // Subtract an error result
+ assert_eq!(res, sub_err);
+ }
+
+ #[test]
+ fn test_op_assign_signed_amount() {
+ let ssat = SignedAmount::from_sat_i32(50);
+
+ let mut res = ssat + ssat;
+ res += SignedAmount::from_sat_i32(-30);
+ assert_eq!(res, NumOpResult::Valid(SignedAmount::from_sat_i32(70)));
+
+ let add_err = NumOpResult::Error(NumOpError::while_doing(MathOp::Add));
+ res += add_err; // Add an error result
+ assert_eq!(res, add_err);
+
+ let mut res = ssat + ssat;
+ res -= SignedAmount::from_sat_i32(25);
+ assert_eq!(res, NumOpResult::Valid(SignedAmount::from_sat_i32(75)));
+
+ let sub_err = NumOpResult::Error(NumOpError::while_doing(MathOp::Sub));
+ res -= sub_err; // Subtract an error result
+ assert_eq!(res, sub_err);
+ }
+
+ #[test]
+ fn test_op_assign_amount_error() {
+ let mut res: NumOpResult<Amount> = NumOpResult::Error(NumOpError::while_doing(MathOp::Add));
+
+ // Adding a valid amount to an error should make an Add error
+ res += Amount::from_sat_u32(10);
+ assert_eq!(res, NumOpResult::Error(NumOpError::while_doing(MathOp::Add)));
+
+ // Adding an error to an error change to an Add error
+ res += NumOpResult::Error(NumOpError::while_doing(MathOp::Sub));
+ assert_eq!(res, NumOpResult::Error(NumOpError::while_doing(MathOp::Add)));
+
+ // Subtracting a valid amount from an error should make a Sub error
+ res -= Amount::from_sat_u32(10);
+ assert_eq!(res, NumOpResult::Error(NumOpError::while_doing(MathOp::Sub)));
+
+ // Subtracting an error from an error change to a Sub error
+ res -= NumOpResult::Error(NumOpError::while_doing(MathOp::Add));
+ assert_eq!(res, NumOpResult::Error(NumOpError::while_doing(MathOp::Sub)));
+ }
}
diff --git a/units/src/internal_macros.rs b/units/src/internal_macros.rs
index df8c5653..02c44f54 100644
--- a/units/src/internal_macros.rs
+++ b/units/src/internal_macros.rs
@@ -83,6 +83,60 @@ macro_rules! impl_add_assign {
}
pub(crate) use impl_add_assign;
+/// Implement `ops::AddAssign` for `$ty` and `NumOpResult<$ty>` on `NumOpResult<$ty>`
+///
+/// This implements the same logic as the generic `NumOpResult` implementation in result.rs,
+/// but works for types that can't implement `AddAssign` on themselves (e.g. `Amount`, `SignedAmount`)
+macro_rules! impl_add_assign_for_results {
+ ($ty:ident) => {
+ impl ops::AddAssign<$ty> for NumOpResult<$ty> {
+ fn add_assign(&mut self, rhs: $ty) {
+ match self {
+ Self::Error(_) => *self = Self::Error(NumOpError::while_doing(MathOp::Add)),
+ Self::Valid(ref lhs) => *self = lhs + rhs
+ }
+ }
+ }
+
+ impl ops::AddAssign<Self> for NumOpResult<$ty> {
+ fn add_assign(&mut self, rhs: Self) {
+ match (&self, rhs) {
+ (Self::Valid(_), Self::Valid(rhs)) => *self += rhs,
+ (_, _) => *self = Self::Error(NumOpError::while_doing(MathOp::Add)),
+ }
+ }
+ }
+ };
+}
+pub(crate) use impl_add_assign_for_results;
+
+/// Implement `ops::SubAssign` for `$ty` and `NumOpResult<$ty>` on `NumOpResult<$ty>`
+///
+/// This implements the same logic as the generic `NumOpResult` implementation in result.rs,
+/// but works for types that can't implement `SubAssign` on themselves (e.g. `Amount`, `SignedAmount`)
+macro_rules! impl_sub_assign_for_results {
+ ($ty:ident) => {
+ impl ops::SubAssign<$ty> for NumOpResult<$ty> {
+ fn sub_assign(&mut self, rhs: $ty) {
+ match self {
+ Self::Error(_) => *self = Self::Error(NumOpError::while_doing(MathOp::Sub)),
+ Self::Valid(ref lhs) => *self = lhs - rhs
+ }
+ }
+ }
+
+ impl ops::SubAssign<Self> for NumOpResult<$ty> {
+ fn sub_assign(&mut self, rhs: Self) {
+ match (&self, rhs) {
+ (Self::Valid(_), Self::Valid(rhs)) => *self -= rhs,
+ (_, _) => *self = Self::Error(NumOpError::while_doing(MathOp::Sub)),
+ }
+ }
+ }
+ };
+}
+pub(crate) use impl_sub_assign_for_results;
+
/// Implement `ops::SubAssign` for `$ty` and `&$ty`.
macro_rules! impl_sub_assign {
($ty:ident) => {
Why this scored 18/100
Community notes
Notes can correct, qualify, or add evidence to the AI analysis. Every note shown here has been validated by a human moderator.
The AI analysis stands alone for now. Submit a note if you can add evidence or important context.