Skip to content

Commit fe577cd

Browse files
committed
Implement Div<NonZeroU64|I64> for Amount, SignedAmount, FeeRate, and Weight
Adds an implementation of div by NonZeroU64 for Amount, FeeRate, and Weight types. Also adds a div by NonZeroI64 for SignedAmount. The operations helps to prevent div-by-zero errors at compile time, rather than runtime. It follows same pattern as existing div operations but leverages safety guarantees offered by non-zero types
1 parent 7ca45e8 commit fe577cd

File tree

4 files changed

+68
-0
lines changed

4 files changed

+68
-0
lines changed

units/src/amount/result.rs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
//! Provides a monodic type returned by mathematical operations (`core::ops`).
44
5+
use core::num::{NonZeroI64, NonZeroU64};
56
use core::ops;
67

78
use NumOpResult as R;
@@ -90,7 +91,11 @@ crate::internal_macros::impl_op_for_references! {
9091
self.to_sat().checked_div(rhs.to_sat()).valid_or_error(MathOp::Div)
9192
}
9293
}
94+
impl ops::Div<NonZeroU64> for Amount {
95+
type Output = Amount;
9396

97+
fn div(self, rhs: NonZeroU64) -> Self::Output { Self::from_sat(self.to_sat() / rhs.get()).expect("construction after division cannot fail") }
98+
}
9499
impl ops::Rem<u64> for Amount {
95100
type Output = NumOpResult<Amount>;
96101

@@ -167,7 +172,11 @@ crate::internal_macros::impl_op_for_references! {
167172
self.to_sat().checked_div(rhs.to_sat()).valid_or_error(MathOp::Div)
168173
}
169174
}
175+
impl ops::Div<NonZeroI64> for SignedAmount {
176+
type Output = SignedAmount;
170177

178+
fn div(self, rhs: NonZeroI64) -> Self::Output { Self::from_sat(self.to_sat() / rhs.get()).expect("construction after division cannot fail") }
179+
}
171180
impl ops::Rem<i64> for SignedAmount {
172181
type Output = NumOpResult<SignedAmount>;
173182

units/src/amount/tests.rs

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
use alloc::format;
77
#[cfg(feature = "alloc")]
88
use alloc::string::{String, ToString};
9+
use core::num::{NonZeroI64, NonZeroU64};
910
#[cfg(feature = "std")]
1011
use std::panic;
1112

@@ -1530,3 +1531,26 @@ fn math_op_errors() {
15301531
panic!("Expected a division by zero error, but got a valid result");
15311532
}
15321533
}
1534+
1535+
#[test]
1536+
#[allow(clippy::op_ref)]
1537+
fn amount_div_nonzero() {
1538+
let amount = Amount::from_sat(100).unwrap();
1539+
let divisor = NonZeroU64::new(4).unwrap();
1540+
let result = amount / divisor;
1541+
assert_eq!(result, Amount::from_sat(25).unwrap());
1542+
//checking also for &T/&U variant
1543+
assert_eq!(&amount / &divisor, Amount::from_sat(25).unwrap());
1544+
}
1545+
1546+
#[test]
1547+
#[allow(clippy::op_ref)]
1548+
fn signed_amount_div_nonzero() {
1549+
let signed = SignedAmount::from_sat(-100).unwrap();
1550+
let divisor = NonZeroI64::new(4).unwrap();
1551+
let result = signed / divisor;
1552+
assert_eq!(result, SignedAmount::from_sat(-25).unwrap());
1553+
//checking also for &T/U, T/&Uvariant
1554+
assert_eq!(&signed / divisor, SignedAmount::from_sat(-25).unwrap());
1555+
assert_eq!(signed / &divisor, SignedAmount::from_sat(-25).unwrap());
1556+
}

units/src/fee_rate/mod.rs

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
#[cfg(feature = "serde")]
66
pub mod serde;
77

8+
use core::num::NonZeroU64;
89
use core::{fmt, ops};
910

1011
#[cfg(feature = "arbitrary")]
@@ -157,6 +158,12 @@ crate::internal_macros::impl_op_for_references! {
157158

158159
fn sub(self, rhs: FeeRate) -> Self::Output { FeeRate::from_sat_per_kwu(self.to_sat_per_kwu() - rhs.to_sat_per_kwu()) }
159160
}
161+
162+
impl ops::Div<NonZeroU64> for FeeRate {
163+
type Output = FeeRate;
164+
165+
fn div(self, rhs: NonZeroU64) -> Self::Output{ Self::from_sat_per_kwu(self.to_sat_per_kwu() / rhs.get()) }
166+
}
160167
}
161168
crate::internal_macros::impl_add_assign!(FeeRate);
162169
crate::internal_macros::impl_sub_assign!(FeeRate);
@@ -198,13 +205,23 @@ impl<'a> Arbitrary<'a> for FeeRate {
198205
#[cfg(test)]
199206
mod tests {
200207
use super::*;
208+
use core::num::NonZeroU64;
201209

202210
#[test]
203211
fn sanity_check() {
204212
let fee_rate: u64 = u64::from(FeeRate::from_sat_per_kwu(100));
205213
assert_eq!(fee_rate, 100_u64);
206214
}
207215

216+
#[test]
217+
#[allow(clippy::op_ref)]
218+
fn feerate_div_nonzero() {
219+
let rate = FeeRate::from_sat_per_kwu(200);
220+
let divisor = NonZeroU64::new(2).unwrap();
221+
assert_eq!(rate / divisor, FeeRate::from_sat_per_kwu(100));
222+
assert_eq!(&rate / &divisor, FeeRate::from_sat_per_kwu(100));
223+
}
224+
208225
#[test]
209226
#[allow(clippy::op_ref)]
210227
fn addition() {

units/src/weight.rs

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
//! Implements `Weight` and associated features.
44
5+
use core::num::NonZeroU64;
56
use core::{fmt, ops};
67

78
#[cfg(feature = "arbitrary")]
@@ -221,6 +222,11 @@ crate::internal_macros::impl_op_for_references! {
221222

222223
fn rem(self, rhs: Weight) -> Self::Output { self.to_wu() % rhs.to_wu() }
223224
}
225+
impl ops::Div<NonZeroU64> for Weight {
226+
type Output = Weight;
227+
228+
fn div(self, rhs: NonZeroU64) -> Self::Output{ Self::from_wu(self.to_wu() / rhs.get()) }
229+
}
224230
}
225231
crate::internal_macros::impl_add_assign!(Weight);
226232
crate::internal_macros::impl_sub_assign!(Weight);
@@ -268,6 +274,7 @@ impl<'a> Arbitrary<'a> for Weight {
268274
#[cfg(test)]
269275
mod tests {
270276
use super::*;
277+
use core::num::NonZeroU64;
271278

272279
const ONE: Weight = Weight::from_wu(1);
273280
const TWO: Weight = Weight::from_wu(2);
@@ -278,6 +285,17 @@ mod tests {
278285
assert_eq!(Weight::MIN_TRANSACTION, Weight::from_wu(240));
279286
}
280287

288+
#[test]
289+
#[allow(clippy::op_ref)]
290+
fn weight_div_nonzero() {
291+
let w = Weight::from_wu(100);
292+
let divisor = NonZeroU64::new(4).unwrap();
293+
assert_eq!(w / divisor, Weight::from_wu(25));
294+
// for borrowed variants
295+
assert_eq!(&w / &divisor, Weight::from_wu(25));
296+
assert_eq!(w / &divisor, Weight::from_wu(25));
297+
}
298+
281299
#[test]
282300
fn from_kwu() {
283301
let got = Weight::from_kwu(1).unwrap();

0 commit comments

Comments
 (0)