Skip to content

Commit

Permalink
Constify Amount, Weight, and FeeRate
Browse files Browse the repository at this point in the history
Methods of these can be obviously `const` but need to handle errors
using `match`/`if` instead of combinators.
  • Loading branch information
Kixunil committed Apr 25, 2023
1 parent 507e070 commit 30c838d
Show file tree
Hide file tree
Showing 3 changed files with 63 additions and 18 deletions.
16 changes: 8 additions & 8 deletions bitcoin/src/amount.rs
Original file line number Diff line number Diff line change
Expand Up @@ -499,7 +499,7 @@ impl Amount {
pub const fn from_sat(satoshi: u64) -> Amount { Amount(satoshi) }

/// Gets the number of satoshis in this [`Amount`].
pub fn to_sat(self) -> u64 { self.0 }
pub const fn to_sat(self) -> u64 { self.0 }

/// The maximum value of an [Amount].
pub const fn max_value() -> Amount { Amount(u64::max_value()) }
Expand Down Expand Up @@ -645,7 +645,7 @@ impl Amount {
pub fn checked_rem(self, rhs: u64) -> Option<Amount> { self.0.checked_rem(rhs).map(Amount) }

/// Convert to a signed amount.
pub fn to_signed(self) -> Result<SignedAmount, ParseAmountError> {
pub const fn to_signed(self) -> Result<SignedAmount, ParseAmountError> {
if self.to_sat() > SignedAmount::max_value().to_sat() as u64 {
Err(ParseAmountError::TooBig)
} else {
Expand Down Expand Up @@ -834,7 +834,7 @@ impl SignedAmount {
pub const fn from_sat(satoshi: i64) -> SignedAmount { SignedAmount(satoshi) }

/// Gets the number of satoshis in this [`SignedAmount`].
pub fn to_sat(self) -> i64 { self.0 }
pub const fn to_sat(self) -> i64 { self.0 }

/// The maximum value of an [SignedAmount].
pub const fn max_value() -> SignedAmount { SignedAmount(i64::max_value()) }
Expand Down Expand Up @@ -954,22 +954,22 @@ impl SignedAmount {
// Some arithmetic that doesn't fit in `core::ops` traits.

/// Get the absolute value of this [SignedAmount].
pub fn abs(self) -> SignedAmount { SignedAmount(self.0.abs()) }
pub const fn abs(self) -> SignedAmount { SignedAmount(self.0.abs()) }

/// Returns a number representing sign of this [SignedAmount].
///
/// - `0` if the amount is zero
/// - `1` if the amount is positive
/// - `-1` if the amount is negative
pub fn signum(self) -> i64 { self.0.signum() }
pub const fn signum(self) -> i64 { self.0.signum() }

/// Returns `true` if this [SignedAmount] is positive and `false` if
/// this [SignedAmount] is zero or negative.
pub fn is_positive(self) -> bool { self.0.is_positive() }
pub const fn is_positive(self) -> bool { self.0.is_positive() }

/// Returns `true` if this [SignedAmount] is negative and `false` if
/// this [SignedAmount] is zero or positive.
pub fn is_negative(self) -> bool { self.0.is_negative() }
pub const fn is_negative(self) -> bool { self.0.is_negative() }

/// Get the absolute value of this [SignedAmount].
/// Returns [None] if overflow occurred. (`self == min_value()`)
Expand Down Expand Up @@ -1018,7 +1018,7 @@ impl SignedAmount {
}

/// Convert to an unsigned amount.
pub fn to_unsigned(self) -> Result<Amount, ParseAmountError> {
pub const fn to_unsigned(self) -> Result<Amount, ParseAmountError> {
if self.is_negative() {
Err(ParseAmountError::Negative)
} else {
Expand Down
22 changes: 18 additions & 4 deletions bitcoin/src/blockdata/fee_rate.rs
Original file line number Diff line number Diff line change
Expand Up @@ -47,11 +47,14 @@ impl FeeRate {
/// # Errors
///
/// Returns `None` on arithmetic overflow.
pub fn from_sat_per_vb(sat_vb: u64) -> Option<Self> {
pub const fn from_sat_per_vb(sat_vb: u64) -> Option<Self> {
// 1 vb == 4 wu
// 1 sat/vb == 1/4 sat/wu
// sat_vb sat/vb * 1000 / 4 == sat/kwu
Some(FeeRate(sat_vb.checked_mul(1000 / 4)?))
match sat_vb.checked_mul(1000 / 4) {
Some(fee_rate) => Some(FeeRate(fee_rate)),
None => None,
}
}

/// Constructs `FeeRate` from satoshis per virtual bytes without overflow check.
Expand All @@ -71,12 +74,23 @@ impl FeeRate {
/// Checked multiplication.
///
/// Computes `self * rhs` returning `None` if overflow occurred.
pub fn checked_mul(self, rhs: u64) -> Option<Self> { self.0.checked_mul(rhs).map(Self) }
pub const fn checked_mul(self, rhs: u64) -> Option<Self> {
match self.0.checked_mul(rhs) {
Some(fee_rate) => Some(Self(fee_rate)),
None => None,
}
}

/// Checked division.
///
/// Computes `self / rhs` returning `None` if `rhs == 0`.
pub fn checked_div(self, rhs: u64) -> Option<Self> { self.0.checked_div(rhs).map(Self) }
pub const fn checked_div(self, rhs: u64) -> Option<Self> {
if rhs == 0 {
None
} else {
Some(Self(self.0 / rhs))
}
}
}

/// Alternative will display the unit.
Expand Down
43 changes: 37 additions & 6 deletions bitcoin/src/blockdata/weight.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,14 +33,24 @@ impl Weight {
pub const fn from_wu(wu: u64) -> Self { Weight(wu) }

/// Constructs `Weight` from kilo weight units returning `None` if overflow occurred.
pub fn from_kwu(wu: u64) -> Option<Self> { wu.checked_mul(1000).map(Weight) }
pub const fn from_kwu(kwu: u64) -> Option<Self> {
match kwu.checked_mul(1000) {
Some(weight) => Some(Weight(weight)),
None => None,
}
}

/// Constructs `Weight` from virtual bytes.
///
/// # Errors
///
/// Returns `None` on overflow.
pub fn from_vb(vb: u64) -> Option<Self> { vb.checked_mul(4).map(Weight::from_wu) }
pub const fn from_vb(vb: u64) -> Option<Self> {
match vb.checked_mul(4) {
Some(weight) => Some(Weight(weight)),
None => None,
}
}

/// Constructs `Weight` from virtual bytes without overflow check.
pub const fn from_vb_unchecked(vb: u64) -> Self { Weight::from_wu(vb * 4) }
Expand Down Expand Up @@ -70,22 +80,43 @@ impl Weight {
/// Checked addition.
///
/// Computes `self + rhs` returning `None` if overflow occurred.
pub fn checked_add(self, rhs: Self) -> Option<Self> { self.0.checked_add(rhs.0).map(Self) }
pub const fn checked_add(self, rhs: Self) -> Option<Self> {
match self.0.checked_add(rhs.0) {
Some(weight) => Some(Self(weight)),
None => None,
}
}

/// Checked subtraction.
///
/// Computes `self - rhs` returning `None` if overflow occurred.
pub fn checked_sub(self, rhs: Self) -> Option<Self> { self.0.checked_sub(rhs.0).map(Self) }
pub const fn checked_sub(self, rhs: Self) -> Option<Self> {
match self.0.checked_sub(rhs.0) {
Some(weight) => Some(Self(weight)),
None => None,
}
}

/// Checked multiplication.
///
/// Computes `self * rhs` returning `None` if overflow occurred.
pub fn checked_mul(self, rhs: u64) -> Option<Self> { self.0.checked_mul(rhs).map(Self) }
pub const fn checked_mul(self, rhs: u64) -> Option<Self> {
match self.0.checked_mul(rhs) {
Some(weight) => Some(Self(weight)),
None => None,
}
}

/// Checked division.
///
/// Computes `self / rhs` returning `None` if `rhs == 0`.
pub fn checked_div(self, rhs: u64) -> Option<Self> { self.0.checked_div(rhs).map(Self) }
pub const fn checked_div(self, rhs: u64) -> Option<Self> {
if rhs != 0 {
Some(Weight(self.0 / rhs))
} else {
None
}
}
}

/// Alternative will display the unit.
Expand Down

0 comments on commit 30c838d

Please sign in to comment.