units: Return NumOpResult when implementing Div
Currently we use a std numeric type for the output of various `Div` implementations while other ops use `NumOpResult`. This makes it difficult to chain operations. Throughout the crate use `Output = NumOpResult<Foo>` when implementing `Div`. Later we want to enable users differentiating between an overflow and a div-by-zero. Explicitly do not implement that yet, done separately to assist review.
This commit is contained in:
parent
dba61c9efe
commit
5fb64953c5
|
@ -83,9 +83,11 @@ crate::internal_macros::impl_op_for_references! {
|
||||||
fn div(self, rhs: u64) -> Self::Output { self.and_then(|lhs| lhs / rhs) }
|
fn div(self, rhs: u64) -> Self::Output { self.and_then(|lhs| lhs / rhs) }
|
||||||
}
|
}
|
||||||
impl ops::Div<Amount> for Amount {
|
impl ops::Div<Amount> for Amount {
|
||||||
type Output = u64;
|
type Output = NumOpResult<u64>;
|
||||||
|
|
||||||
fn div(self, rhs: Amount) -> Self::Output { self.to_sat() / rhs.to_sat() }
|
fn div(self, rhs: Amount) -> Self::Output {
|
||||||
|
self.to_sat().checked_div(rhs.to_sat()).valid_or_error()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ops::Rem<u64> for Amount {
|
impl ops::Rem<u64> for Amount {
|
||||||
|
@ -158,9 +160,11 @@ crate::internal_macros::impl_op_for_references! {
|
||||||
fn div(self, rhs: i64) -> Self::Output { self.and_then(|lhs| lhs / rhs) }
|
fn div(self, rhs: i64) -> Self::Output { self.and_then(|lhs| lhs / rhs) }
|
||||||
}
|
}
|
||||||
impl ops::Div<SignedAmount> for SignedAmount {
|
impl ops::Div<SignedAmount> for SignedAmount {
|
||||||
type Output = i64;
|
type Output = NumOpResult<i64>;
|
||||||
|
|
||||||
fn div(self, rhs: SignedAmount) -> Self::Output { self.to_sat() / rhs.to_sat() }
|
fn div(self, rhs: SignedAmount) -> Self::Output {
|
||||||
|
self.to_sat().checked_div(rhs.to_sat()).valid_or_error()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ops::Rem<i64> for SignedAmount {
|
impl ops::Rem<i64> for SignedAmount {
|
||||||
|
|
|
@ -1231,27 +1231,31 @@ fn op_int_combos() {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn unsigned_amount_div_by_amount() {
|
fn unsigned_amount_div_by_amount() {
|
||||||
assert_eq!(sat(0) / sat(7), 0);
|
assert_eq!((sat(0) / sat(7)).unwrap(), 0);
|
||||||
assert_eq!(sat(1897) / sat(7), 271);
|
assert_eq!((sat(1897) / sat(7)).unwrap(), 271);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
#[should_panic(expected = "attempt to divide by zero")]
|
fn unsigned_amount_div_by_amount_zero() {
|
||||||
fn unsigned_amount_div_by_amount_zero() { let _ = sat(1897) / Amount::ZERO; }
|
let res = sat(1897) / Amount::ZERO;
|
||||||
|
assert!(res.into_result().is_err());
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn signed_amount_div_by_amount() {
|
fn signed_amount_div_by_amount() {
|
||||||
assert_eq!(ssat(0) / ssat(7), 0);
|
assert_eq!((ssat(0) / ssat(7)).unwrap(), 0);
|
||||||
|
|
||||||
assert_eq!(ssat(1897) / ssat(7), 271);
|
assert_eq!((ssat(1897) / ssat(7)).unwrap(), 271);
|
||||||
assert_eq!(ssat(1897) / ssat(-7), -271);
|
assert_eq!((ssat(1897) / ssat(-7)).unwrap(), -271);
|
||||||
assert_eq!(ssat(-1897) / ssat(7), -271);
|
assert_eq!((ssat(-1897) / ssat(7)).unwrap(), -271);
|
||||||
assert_eq!(ssat(-1897) / ssat(-7), 271);
|
assert_eq!((ssat(-1897) / ssat(-7)).unwrap(), 271);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
#[should_panic(expected = "attempt to divide by zero")]
|
fn signed_amount_div_by_amount_zero() {
|
||||||
fn signed_amount_div_by_amount_zero() { let _ = ssat(1897) / SignedAmount::ZERO; }
|
let res = ssat(1897) / SignedAmount::ZERO;
|
||||||
|
assert!(res.into_result().is_err());
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn check_const() {
|
fn check_const() {
|
||||||
|
|
|
@ -178,18 +178,18 @@ crate::internal_macros::impl_op_for_references! {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ops::Div<Weight> for Amount {
|
impl ops::Div<Weight> for Amount {
|
||||||
type Output = FeeRate;
|
type Output = NumOpResult<FeeRate>;
|
||||||
|
|
||||||
fn div(self, rhs: Weight) -> Self::Output {
|
fn div(self, rhs: Weight) -> Self::Output {
|
||||||
FeeRate::from_sat_per_kwu(self.to_sat() * 1000 / rhs.to_wu())
|
self.checked_div_by_weight_floor(rhs).valid_or_error()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ops::Div<FeeRate> for Amount {
|
impl ops::Div<FeeRate> for Amount {
|
||||||
type Output = Weight;
|
type Output = NumOpResult<Weight>;
|
||||||
|
|
||||||
fn div(self, rhs: FeeRate) -> Self::Output {
|
fn div(self, rhs: FeeRate) -> Self::Output {
|
||||||
self.checked_div_by_fee_rate_floor(rhs).unwrap()
|
self.checked_div_by_fee_rate_floor(rhs).valid_or_error()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -215,7 +215,7 @@ mod tests {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn fee_rate_div_by_weight() {
|
fn fee_rate_div_by_weight() {
|
||||||
let fee_rate = Amount::from_sat_u32(329) / Weight::from_wu(381);
|
let fee_rate = (Amount::from_sat_u32(329) / Weight::from_wu(381)).unwrap();
|
||||||
assert_eq!(fee_rate, FeeRate::from_sat_per_kwu(863));
|
assert_eq!(fee_rate, FeeRate::from_sat_per_kwu(863));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -275,21 +275,21 @@ mod tests {
|
||||||
// Test exact division
|
// Test exact division
|
||||||
let amount = Amount::from_sat_u32(1000);
|
let amount = Amount::from_sat_u32(1000);
|
||||||
let fee_rate = FeeRate::from_sat_per_kwu(2);
|
let fee_rate = FeeRate::from_sat_per_kwu(2);
|
||||||
let weight = amount / fee_rate;
|
let weight = (amount / fee_rate).unwrap();
|
||||||
assert_eq!(weight, Weight::from_wu(500_000));
|
assert_eq!(weight, Weight::from_wu(500_000));
|
||||||
|
|
||||||
// Test reference division
|
// Test reference division
|
||||||
let weight_ref = &amount / fee_rate;
|
let weight_ref = (&amount / fee_rate).unwrap();
|
||||||
assert_eq!(weight_ref, Weight::from_wu(500_000));
|
assert_eq!(weight_ref, Weight::from_wu(500_000));
|
||||||
let weight_ref2 = amount / &fee_rate;
|
let weight_ref2 = (amount / &fee_rate).unwrap();
|
||||||
assert_eq!(weight_ref2, Weight::from_wu(500_000));
|
assert_eq!(weight_ref2, Weight::from_wu(500_000));
|
||||||
let weight_ref3 = &amount / &fee_rate;
|
let weight_ref3 = (&amount / &fee_rate).unwrap();
|
||||||
assert_eq!(weight_ref3, Weight::from_wu(500_000));
|
assert_eq!(weight_ref3, Weight::from_wu(500_000));
|
||||||
|
|
||||||
// Test truncation behavior
|
// Test truncation behavior
|
||||||
let amount = Amount::from_sat_u32(1000);
|
let amount = Amount::from_sat_u32(1000);
|
||||||
let fee_rate = FeeRate::from_sat_per_kwu(3);
|
let fee_rate = FeeRate::from_sat_per_kwu(3);
|
||||||
let weight = amount / fee_rate;
|
let weight = (amount / fee_rate).unwrap();
|
||||||
// 1000 * 1000 = 1,000,000 msats
|
// 1000 * 1000 = 1,000,000 msats
|
||||||
// 1,000,000 / 3 = 333,333.33... wu
|
// 1,000,000 / 3 = 333,333.33... wu
|
||||||
// Should truncate down to 333,333 wu
|
// Should truncate down to 333,333 wu
|
||||||
|
|
|
@ -6,7 +6,7 @@ use core::fmt;
|
||||||
|
|
||||||
use NumOpResult as R;
|
use NumOpResult as R;
|
||||||
|
|
||||||
use crate::{Amount, SignedAmount};
|
use crate::{Amount, FeeRate, SignedAmount, Weight};
|
||||||
|
|
||||||
/// Result of a mathematical operation on two numeric types.
|
/// Result of a mathematical operation on two numeric types.
|
||||||
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
|
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
|
||||||
|
@ -125,7 +125,7 @@ macro_rules! impl_opt_ext {
|
||||||
)*
|
)*
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
impl_opt_ext!(Amount, SignedAmount);
|
impl_opt_ext!(Amount, SignedAmount, u64, i64, FeeRate, Weight);
|
||||||
|
|
||||||
/// An error occurred while doing a mathematical operation.
|
/// An error occurred while doing a mathematical operation.
|
||||||
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
|
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
|
||||||
|
|
Loading…
Reference in New Issue