From 0a9f14f7b036c5232449d058fb6d425c8376d87a Mon Sep 17 00:00:00 2001 From: "Tobin C. Harding" Date: Mon, 3 Mar 2025 08:00:14 +1100 Subject: [PATCH] Implement Div by amount for amount types It is semantically valid to divide an amount by another amount. The result of the operation is an integer. Note that we cannot implement `Div` by `NumOpResult` because there is no way to show the div by invalid case. Implement `Div` by amount for both amount types. --- units/src/amount/result.rs | 10 ++++++++++ units/src/amount/tests.rs | 32 ++++++++++++++++++++++++++++++++ 2 files changed, 42 insertions(+) diff --git a/units/src/amount/result.rs b/units/src/amount/result.rs index 5f1d7742b..be106d6b1 100644 --- a/units/src/amount/result.rs +++ b/units/src/amount/result.rs @@ -182,6 +182,11 @@ crate::internal_macros::impl_op_for_references! { fn div(self, rhs: u64) -> Self::Output { self.and_then(|lhs| lhs / rhs) } } + impl ops::Div for Amount { + type Output = u64; + + fn div(self, rhs: Amount) -> Self::Output { self.to_sat() / rhs.to_sat() } + } impl ops::Rem for Amount { type Output = NumOpResult; @@ -252,6 +257,11 @@ crate::internal_macros::impl_op_for_references! { fn div(self, rhs: i64) -> Self::Output { self.and_then(|lhs| lhs / rhs) } } + impl ops::Div for SignedAmount { + type Output = i64; + + fn div(self, rhs: SignedAmount) -> Self::Output { self.to_sat() / rhs.to_sat() } + } impl ops::Rem for SignedAmount { type Output = NumOpResult; diff --git a/units/src/amount/tests.rs b/units/src/amount/tests.rs index 4a87ba420..b3e859341 100644 --- a/units/src/amount/tests.rs +++ b/units/src/amount/tests.rs @@ -1282,6 +1282,38 @@ fn op_int_combos() { assert_eq!(sres(1901) % 7, sres(4)); } +#[test] +fn unsigned_amount_div_by_amount() { + let sat = Amount::from_sat; + + assert_eq!(sat(0) / sat(7), 0); + assert_eq!(sat(1897) / sat(7), 271); +} + +#[test] +#[should_panic(expected = "attempt to divide by zero")] +fn unsigned_amount_div_by_amount_zero() { + let _ = Amount::from_sat(1897) / Amount::ZERO; +} + +#[test] +fn signed_amount_div_by_amount() { + let ssat = SignedAmount::from_sat; + + assert_eq!(ssat(0) / ssat(7), 0); + + assert_eq!(ssat(1897) / ssat(7), 271); + assert_eq!(ssat(1897) / ssat(-7), -271); + assert_eq!(ssat(-1897) / ssat(7), -271); + assert_eq!(ssat(-1897) / ssat(-7), 271); +} + +#[test] +#[should_panic(expected = "attempt to divide by zero")] +fn signed_amount_div_by_amount_zero() { + let _ = SignedAmount::from_sat(1897) / SignedAmount::ZERO; +} + #[test] fn check_const() { assert_eq!(SignedAmount::ONE_BTC.to_sat(), 100_000_000);