Merge rust-bitcoin/rust-bitcoin#4461: Implementing Div<NonZeroU64|I64> for Amount, SignedAmount, FeeRate, and and Weight

fe577cd04e Implement Div<NonZeroU64|I64> for Amount, SignedAmount, FeeRate, and Weight (frankomosh)

Pull request description:

  The pr implements `Div<NonZeroU64>` and `Div<NonZeroI64>` for the following types in `units` crate: `Amount`, `SignedAmount`, `FeeRate`, `Weight`

  For handling owned/borrowed variants, each impl is wrapped in the existing `impl_op_for_references!` macro, which generates: `T  / NonZero*` , `&T / NonZero*`, `T  / &NonZero*`, `&T / &NonZero*`

  close: #4442

ACKs for top commit:
  Kixunil:
    ACK fe577cd04e
  apoelstra:
    ACK fe577cd04e64488371aa62b872e2b88050d4948f; successfully ran local tests
  tcharding:
    ACK fe577cd04e

Tree-SHA512: b9b4a9f46d2fcf559d0a7f62ec397b6c2b174dd8ca9d80b37c0c393894ab4bc32019d64e2afcad1f780442b16aa3d15240ce607fc14b5e17b112243f7556b5b4
This commit is contained in:
merge-script 2025-05-14 00:56:25 +00:00
commit fc373f3a37
No known key found for this signature in database
GPG Key ID: C588D63CE41B97C1
4 changed files with 68 additions and 0 deletions

View File

@ -2,6 +2,7 @@
//! Provides a monodic type returned by mathematical operations (`core::ops`).
use core::num::{NonZeroI64, NonZeroU64};
use core::ops;
use NumOpResult as R;
@ -90,7 +91,11 @@ crate::internal_macros::impl_op_for_references! {
self.to_sat().checked_div(rhs.to_sat()).valid_or_error(MathOp::Div)
}
}
impl ops::Div<NonZeroU64> for Amount {
type Output = Amount;
fn div(self, rhs: NonZeroU64) -> Self::Output { Self::from_sat(self.to_sat() / rhs.get()).expect("construction after division cannot fail") }
}
impl ops::Rem<u64> for Amount {
type Output = NumOpResult<Amount>;
@ -167,7 +172,11 @@ crate::internal_macros::impl_op_for_references! {
self.to_sat().checked_div(rhs.to_sat()).valid_or_error(MathOp::Div)
}
}
impl ops::Div<NonZeroI64> for SignedAmount {
type Output = SignedAmount;
fn div(self, rhs: NonZeroI64) -> Self::Output { Self::from_sat(self.to_sat() / rhs.get()).expect("construction after division cannot fail") }
}
impl ops::Rem<i64> for SignedAmount {
type Output = NumOpResult<SignedAmount>;

View File

@ -6,6 +6,7 @@
use alloc::format;
#[cfg(feature = "alloc")]
use alloc::string::{String, ToString};
use core::num::{NonZeroI64, NonZeroU64};
#[cfg(feature = "std")]
use std::panic;
@ -1530,3 +1531,26 @@ fn math_op_errors() {
panic!("Expected a division by zero error, but got a valid result");
}
}
#[test]
#[allow(clippy::op_ref)]
fn amount_div_nonzero() {
let amount = Amount::from_sat(100).unwrap();
let divisor = NonZeroU64::new(4).unwrap();
let result = amount / divisor;
assert_eq!(result, Amount::from_sat(25).unwrap());
//checking also for &T/&U variant
assert_eq!(&amount / &divisor, Amount::from_sat(25).unwrap());
}
#[test]
#[allow(clippy::op_ref)]
fn signed_amount_div_nonzero() {
let signed = SignedAmount::from_sat(-100).unwrap();
let divisor = NonZeroI64::new(4).unwrap();
let result = signed / divisor;
assert_eq!(result, SignedAmount::from_sat(-25).unwrap());
//checking also for &T/U, T/&Uvariant
assert_eq!(&signed / divisor, SignedAmount::from_sat(-25).unwrap());
assert_eq!(signed / &divisor, SignedAmount::from_sat(-25).unwrap());
}

View File

@ -5,6 +5,7 @@
#[cfg(feature = "serde")]
pub mod serde;
use core::num::NonZeroU64;
use core::{fmt, ops};
#[cfg(feature = "arbitrary")]
@ -157,6 +158,12 @@ crate::internal_macros::impl_op_for_references! {
fn sub(self, rhs: FeeRate) -> Self::Output { FeeRate::from_sat_per_kwu(self.to_sat_per_kwu() - rhs.to_sat_per_kwu()) }
}
impl ops::Div<NonZeroU64> for FeeRate {
type Output = FeeRate;
fn div(self, rhs: NonZeroU64) -> Self::Output{ Self::from_sat_per_kwu(self.to_sat_per_kwu() / rhs.get()) }
}
}
crate::internal_macros::impl_add_assign!(FeeRate);
crate::internal_macros::impl_sub_assign!(FeeRate);
@ -198,6 +205,7 @@ impl<'a> Arbitrary<'a> for FeeRate {
#[cfg(test)]
mod tests {
use super::*;
use core::num::NonZeroU64;
#[test]
fn sanity_check() {
@ -205,6 +213,15 @@ mod tests {
assert_eq!(fee_rate, 100_u64);
}
#[test]
#[allow(clippy::op_ref)]
fn feerate_div_nonzero() {
let rate = FeeRate::from_sat_per_kwu(200);
let divisor = NonZeroU64::new(2).unwrap();
assert_eq!(rate / divisor, FeeRate::from_sat_per_kwu(100));
assert_eq!(&rate / &divisor, FeeRate::from_sat_per_kwu(100));
}
#[test]
#[allow(clippy::op_ref)]
fn addition() {

View File

@ -2,6 +2,7 @@
//! Implements `Weight` and associated features.
use core::num::NonZeroU64;
use core::{fmt, ops};
#[cfg(feature = "arbitrary")]
@ -221,6 +222,11 @@ crate::internal_macros::impl_op_for_references! {
fn rem(self, rhs: Weight) -> Self::Output { self.to_wu() % rhs.to_wu() }
}
impl ops::Div<NonZeroU64> for Weight {
type Output = Weight;
fn div(self, rhs: NonZeroU64) -> Self::Output{ Self::from_wu(self.to_wu() / rhs.get()) }
}
}
crate::internal_macros::impl_add_assign!(Weight);
crate::internal_macros::impl_sub_assign!(Weight);
@ -268,6 +274,7 @@ impl<'a> Arbitrary<'a> for Weight {
#[cfg(test)]
mod tests {
use super::*;
use core::num::NonZeroU64;
const ONE: Weight = Weight::from_wu(1);
const TWO: Weight = Weight::from_wu(2);
@ -278,6 +285,17 @@ mod tests {
assert_eq!(Weight::MIN_TRANSACTION, Weight::from_wu(240));
}
#[test]
#[allow(clippy::op_ref)]
fn weight_div_nonzero() {
let w = Weight::from_wu(100);
let divisor = NonZeroU64::new(4).unwrap();
assert_eq!(w / divisor, Weight::from_wu(25));
// for borrowed variants
assert_eq!(&w / &divisor, Weight::from_wu(25));
assert_eq!(w / &divisor, Weight::from_wu(25));
}
#[test]
fn from_kwu() {
let got = Weight::from_kwu(1).unwrap();