amount: move MIN/MAX constants and constructors inside the privacy boundary
It's conceptually a bit tortured to have an `Amount` type defined in a private module, with an _unchecked method allowing you to set values out of range, which needs to be used outside of the module to *define* the range and the constructors that check it. Move the constants and constructors inside the privacy module, where they can be written directly. This is easier to understand and eliminates a couple _unchecked calls.
This commit is contained in:
parent
004d073184
commit
d0d7a15604
|
@ -17,6 +17,8 @@ use super::{
|
||||||
};
|
};
|
||||||
|
|
||||||
mod encapsulate {
|
mod encapsulate {
|
||||||
|
use super::OutOfRangeError;
|
||||||
|
|
||||||
/// A signed amount.
|
/// A signed amount.
|
||||||
///
|
///
|
||||||
/// The [`SignedAmount`] type can be used to express Bitcoin amounts that support arithmetic and
|
/// The [`SignedAmount`] type can be used to express Bitcoin amounts that support arithmetic and
|
||||||
|
@ -50,6 +52,11 @@ mod encapsulate {
|
||||||
pub struct SignedAmount(i64);
|
pub struct SignedAmount(i64);
|
||||||
|
|
||||||
impl SignedAmount {
|
impl SignedAmount {
|
||||||
|
/// The maximum value of an amount.
|
||||||
|
pub const MAX: Self = Self(21_000_000 * 100_000_000);
|
||||||
|
/// The minimum value of an amount.
|
||||||
|
pub const MIN: Self = Self(-21_000_000 * 100_000_000);
|
||||||
|
|
||||||
/// Constructs a new [`SignedAmount`] with satoshi precision and the given number of satoshis.
|
/// Constructs a new [`SignedAmount`] with satoshi precision and the given number of satoshis.
|
||||||
///
|
///
|
||||||
/// Caller to guarantee that `satoshi` is within valid range.
|
/// Caller to guarantee that `satoshi` is within valid range.
|
||||||
|
@ -74,6 +81,31 @@ mod encapsulate {
|
||||||
/// assert_eq!(SignedAmount::ONE_BTC.to_sat(), 100_000_000);
|
/// assert_eq!(SignedAmount::ONE_BTC.to_sat(), 100_000_000);
|
||||||
/// ```
|
/// ```
|
||||||
pub const fn to_sat(self) -> i64 { self.0 }
|
pub const fn to_sat(self) -> i64 { self.0 }
|
||||||
|
|
||||||
|
/// Constructs a new [`SignedAmount`] from the given number of satoshis.
|
||||||
|
///
|
||||||
|
/// # Errors
|
||||||
|
///
|
||||||
|
/// If `satoshi` is outside of valid range (see [`Self::MAX_MONEY`]).
|
||||||
|
///
|
||||||
|
/// # Examples
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// # use bitcoin_units::{amount, SignedAmount};
|
||||||
|
/// # let sat = -100_000;
|
||||||
|
/// let amount = SignedAmount::from_sat(sat)?;
|
||||||
|
/// assert_eq!(amount.to_sat(), sat);
|
||||||
|
/// # Ok::<_, amount::OutOfRangeError>(())
|
||||||
|
/// ```
|
||||||
|
pub const fn from_sat(satoshi: i64) -> Result<SignedAmount, OutOfRangeError> {
|
||||||
|
if satoshi < Self::MIN.to_sat() {
|
||||||
|
Err(OutOfRangeError { is_signed: true, is_greater_than_max: false })
|
||||||
|
} else if satoshi > Self::MAX_MONEY.to_sat() {
|
||||||
|
Err(OutOfRangeError { is_signed: true, is_greater_than_max: true })
|
||||||
|
} else {
|
||||||
|
Ok(Self(satoshi))
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#[doc(inline)]
|
#[doc(inline)]
|
||||||
|
@ -89,36 +121,7 @@ impl SignedAmount {
|
||||||
/// Exactly fifty bitcoin.
|
/// Exactly fifty bitcoin.
|
||||||
pub const FIFTY_BTC: Self = SignedAmount::from_btc_i16(50);
|
pub const FIFTY_BTC: Self = SignedAmount::from_btc_i16(50);
|
||||||
/// The maximum value allowed as an amount. Useful for sanity checking.
|
/// The maximum value allowed as an amount. Useful for sanity checking.
|
||||||
pub const MAX_MONEY: Self = SignedAmount::from_sat_unchecked(21_000_000 * 100_000_000);
|
pub const MAX_MONEY: Self = Self::MAX;
|
||||||
/// The minimum value of an amount.
|
|
||||||
pub const MIN: Self = SignedAmount::from_sat_unchecked(-21_000_000 * 100_000_000);
|
|
||||||
/// The maximum value of an amount.
|
|
||||||
pub const MAX: Self = SignedAmount::MAX_MONEY;
|
|
||||||
|
|
||||||
/// Constructs a new [`SignedAmount`] from the given number of satoshis.
|
|
||||||
///
|
|
||||||
/// # Errors
|
|
||||||
///
|
|
||||||
/// If `satoshi` is outside of valid range (see [`Self::MAX_MONEY`]).
|
|
||||||
///
|
|
||||||
/// # Examples
|
|
||||||
///
|
|
||||||
/// ```
|
|
||||||
/// # use bitcoin_units::{amount, SignedAmount};
|
|
||||||
/// # let sat = -100_000;
|
|
||||||
/// let amount = SignedAmount::from_sat(sat)?;
|
|
||||||
/// assert_eq!(amount.to_sat(), sat);
|
|
||||||
/// # Ok::<_, amount::OutOfRangeError>(())
|
|
||||||
/// ```
|
|
||||||
pub const fn from_sat(satoshi: i64) -> Result<SignedAmount, OutOfRangeError> {
|
|
||||||
if satoshi < Self::MIN.to_sat() {
|
|
||||||
Err(OutOfRangeError { is_signed: true, is_greater_than_max: false })
|
|
||||||
} else if satoshi > Self::MAX_MONEY.to_sat() {
|
|
||||||
Err(OutOfRangeError { is_signed: true, is_greater_than_max: true })
|
|
||||||
} else {
|
|
||||||
Ok(SignedAmount::from_sat_unchecked(satoshi))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Converts from a value expressing a decimal number of bitcoin to a [`SignedAmount`].
|
/// Converts from a value expressing a decimal number of bitcoin to a [`SignedAmount`].
|
||||||
///
|
///
|
||||||
|
|
|
@ -17,6 +17,8 @@ use super::{
|
||||||
};
|
};
|
||||||
|
|
||||||
mod encapsulate {
|
mod encapsulate {
|
||||||
|
use super::OutOfRangeError;
|
||||||
|
|
||||||
/// An amount.
|
/// An amount.
|
||||||
///
|
///
|
||||||
/// The [`Amount`] type can be used to express Bitcoin amounts that support arithmetic and
|
/// The [`Amount`] type can be used to express Bitcoin amounts that support arithmetic and
|
||||||
|
@ -50,6 +52,11 @@ mod encapsulate {
|
||||||
pub struct Amount(u64);
|
pub struct Amount(u64);
|
||||||
|
|
||||||
impl Amount {
|
impl Amount {
|
||||||
|
/// The maximum value of an amount.
|
||||||
|
pub const MAX: Self = Self(21_000_000 * 100_000_000);
|
||||||
|
/// The minimum value of an amount.
|
||||||
|
pub const MIN: Self = Self(0);
|
||||||
|
|
||||||
/// Constructs a new [`Amount`] with satoshi precision and the given number of satoshis.
|
/// Constructs a new [`Amount`] with satoshi precision and the given number of satoshis.
|
||||||
///
|
///
|
||||||
/// Caller to guarantee that `satoshi` is within valid range. See [`Self::MAX`].
|
/// Caller to guarantee that `satoshi` is within valid range. See [`Self::MAX`].
|
||||||
|
@ -72,6 +79,29 @@ mod encapsulate {
|
||||||
/// assert_eq!(Amount::ONE_BTC.to_sat(), 100_000_000);
|
/// assert_eq!(Amount::ONE_BTC.to_sat(), 100_000_000);
|
||||||
/// ```
|
/// ```
|
||||||
pub const fn to_sat(self) -> u64 { self.0 }
|
pub const fn to_sat(self) -> u64 { self.0 }
|
||||||
|
|
||||||
|
/// Constructs a new [`Amount`] from the given number of satoshis.
|
||||||
|
///
|
||||||
|
/// # Errors
|
||||||
|
///
|
||||||
|
/// If `satoshi` is outside of valid range (greater than [`Self::MAX_MONEY`]).
|
||||||
|
///
|
||||||
|
/// # Examples
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// # use bitcoin_units::{amount, Amount};
|
||||||
|
/// # let sat = 100_000;
|
||||||
|
/// let amount = Amount::from_sat(sat)?;
|
||||||
|
/// assert_eq!(amount.to_sat(), sat);
|
||||||
|
/// # Ok::<_, amount::OutOfRangeError>(())
|
||||||
|
/// ```
|
||||||
|
pub const fn from_sat(satoshi: u64) -> Result<Amount, OutOfRangeError> {
|
||||||
|
if satoshi > Self::MAX_MONEY.to_sat() {
|
||||||
|
Err(OutOfRangeError { is_signed: false, is_greater_than_max: true })
|
||||||
|
} else {
|
||||||
|
Ok(Self(satoshi))
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#[doc(inline)]
|
#[doc(inline)]
|
||||||
|
@ -87,37 +117,10 @@ impl Amount {
|
||||||
/// Exactly fifty bitcoin.
|
/// Exactly fifty bitcoin.
|
||||||
pub const FIFTY_BTC: Self = Amount::from_btc_u16(50);
|
pub const FIFTY_BTC: Self = Amount::from_btc_u16(50);
|
||||||
/// The maximum value allowed as an amount. Useful for sanity checking.
|
/// The maximum value allowed as an amount. Useful for sanity checking.
|
||||||
pub const MAX_MONEY: Self = Amount::from_sat_unchecked(21_000_000 * 100_000_000);
|
pub const MAX_MONEY: Self = Amount::MAX;
|
||||||
/// The minimum value of an amount.
|
|
||||||
pub const MIN: Self = Amount::ZERO;
|
|
||||||
/// The maximum value of an amount.
|
|
||||||
pub const MAX: Self = Amount::MAX_MONEY;
|
|
||||||
/// The number of bytes that an amount contributes to the size of a transaction.
|
/// The number of bytes that an amount contributes to the size of a transaction.
|
||||||
pub const SIZE: usize = 8; // Serialized length of a u64.
|
pub const SIZE: usize = 8; // Serialized length of a u64.
|
||||||
|
|
||||||
/// Constructs a new [`Amount`] from the given number of satoshis.
|
|
||||||
///
|
|
||||||
/// # Errors
|
|
||||||
///
|
|
||||||
/// If `satoshi` is outside of valid range (greater than [`Self::MAX_MONEY`]).
|
|
||||||
///
|
|
||||||
/// # Examples
|
|
||||||
///
|
|
||||||
/// ```
|
|
||||||
/// # use bitcoin_units::{amount, Amount};
|
|
||||||
/// # let sat = 100_000;
|
|
||||||
/// let amount = Amount::from_sat(sat)?;
|
|
||||||
/// assert_eq!(amount.to_sat(), sat);
|
|
||||||
/// # Ok::<_, amount::OutOfRangeError>(())
|
|
||||||
/// ```
|
|
||||||
pub const fn from_sat(satoshi: u64) -> Result<Amount, OutOfRangeError> {
|
|
||||||
if satoshi > Self::MAX_MONEY.to_sat() {
|
|
||||||
Err(OutOfRangeError { is_signed: false, is_greater_than_max: true })
|
|
||||||
} else {
|
|
||||||
Ok(Self::from_sat_unchecked(satoshi))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Converts from a value expressing a decimal number of bitcoin to an [`Amount`].
|
/// Converts from a value expressing a decimal number of bitcoin to an [`Amount`].
|
||||||
///
|
///
|
||||||
/// # Errors
|
/// # Errors
|
||||||
|
|
Loading…
Reference in New Issue