diff --git a/units/src/amount/signed.rs b/units/src/amount/signed.rs index a817566e2..2faa7e45f 100644 --- a/units/src/amount/signed.rs +++ b/units/src/amount/signed.rs @@ -19,15 +19,15 @@ use super::{ /// A signed amount. /// /// The [`SignedAmount`] type can be used to express Bitcoin amounts that support arithmetic and -/// conversion to various denominations. The `Amount` type does not implement `serde` traits but we -/// do provide modules for serializing as satoshis or bitcoin. +/// conversion to various denominations. The [`SignedAmount`] type does not implement [`serde`] +/// traits but we do provide modules for serializing as satoshis or bitcoin. /// /// Warning! /// /// This type implements several arithmetic operations from [`core::ops`]. /// To prevent errors due to overflow or underflow when using these operations, /// it is advised to instead use the checked arithmetic methods whose names -/// start with `checked_`. The operations from [`core::ops`] that [`Amount`] +/// start with `checked_`. The operations from [`core::ops`] that [`SignedAmount`] /// implements will panic when overflow or underflow occurs. /// /// # Examples @@ -63,12 +63,41 @@ impl SignedAmount { pub const MAX: Self = SignedAmount::MAX_MONEY; /// Constructs a new [`SignedAmount`] with satoshi precision and the given number of satoshis. + /// + /// # Examples + /// + /// ``` + /// # use bitcoin_units::SignedAmount; + /// let amount = SignedAmount::from_sat(-100_000); + /// assert_eq!(amount.to_sat(), -100_000); + /// ``` pub const fn from_sat(satoshi: i64) -> SignedAmount { SignedAmount(satoshi) } /// Gets the number of satoshis in this [`SignedAmount`]. + /// + /// # Examples + /// + /// ``` + /// # use bitcoin_units::SignedAmount; + /// assert_eq!(SignedAmount::ONE_BTC.to_sat(), 100_000_000); + /// ``` pub const fn to_sat(self) -> i64 { self.0 } - /// Converts from a value expressing a whole number of bitcoin to a [`SignedAmount`]. + /// Converts from a value expressing a decimal number of bitcoin to a [`SignedAmount`]. + /// + /// # Errors + /// + /// If the amount is too big (positive or negative) or too precise. + /// + /// Please be aware of the risk of using floating-point numbers. + /// + /// # Examples + /// + /// ``` + /// # use bitcoin_units::SignedAmount; + /// let amount = SignedAmount::from_btc(-0.01).expect("we know 0.01 is valid"); + /// assert_eq!(amount.to_sat(), -1_000_000); + /// ``` #[cfg(feature = "alloc")] pub fn from_btc(btc: f64) -> Result { SignedAmount::from_float_in(btc, Denomination::Bitcoin) @@ -101,10 +130,14 @@ impl SignedAmount { } } - /// Parses a decimal string as a value in the given denomination. + /// Parses a decimal string as a value in the given [`Denomination`]. /// - /// Note: This only parses the value string. If you want to parse a value - /// with denomination, use [`FromStr`]. + /// Note: This only parses the value string. If you want to parse a string + /// containing the value with denomination, use [`FromStr`]. + /// + /// # Errors + /// + /// If the amount is too big (positive or negative) or too precise. pub fn from_str_in(s: &str, denom: Denomination) -> Result { match parse_signed_to_satoshi(s, denom).map_err(|error| error.convert(true))? { // (negative, amount) @@ -123,20 +156,41 @@ impl SignedAmount { /// or with [`fmt::Display`]. /// /// If you want to parse only the amount without the denomination, use [`Self::from_str_in`]. + /// + /// # Errors + /// + /// If the amount is too big (positive or negative) or too precise. + /// + /// # Examples + /// + /// ``` + /// # use bitcoin_units::{amount, SignedAmount}; + /// let amount = SignedAmount::from_str_with_denomination("0.1 BTC")?; + /// assert_eq!(amount, SignedAmount::from_sat(10_000_000)); + /// # Ok::<_, amount::ParseError>(()) + /// ``` pub fn from_str_with_denomination(s: &str) -> Result { let (amt, denom) = split_amount_and_denomination(s)?; SignedAmount::from_str_in(amt, denom).map_err(Into::into) } - /// Express this [`SignedAmount`] as a floating-point value in the given denomination. + /// Expresses this [`SignedAmount`] as a floating-point value in the given [`Denomination`]. /// /// Please be aware of the risk of using floating-point numbers. + /// + /// # Examples + /// + /// ``` + /// # use bitcoin_units::amount::{SignedAmount, Denomination}; + /// let amount = SignedAmount::from_sat(100_000); + /// assert_eq!(amount.to_float_in(Denomination::Bitcoin), 0.001) + /// ``` #[cfg(feature = "alloc")] pub fn to_float_in(self, denom: Denomination) -> f64 { self.to_string_in(denom).parse::().unwrap() } - /// Express this [`SignedAmount`] as a floating-point value in Bitcoin. + /// Expresses this [`SignedAmount`] as a floating-point value in Bitcoin. /// /// Please be aware of the risk of using floating-point numbers. /// @@ -150,12 +204,11 @@ impl SignedAmount { #[cfg(feature = "alloc")] pub fn to_btc(self) -> f64 { self.to_float_in(Denomination::Bitcoin) } - /// Convert this [`SignedAmount`] in floating-point notation with a given - /// denomination. + /// Converts this [`SignedAmount`] in floating-point notation in the given [`Denomination`]. /// /// # Errors /// - /// If the amount is too big, too precise or negative. + /// If the amount is too big (positive or negative) or too precise. /// /// Please be aware of the risk of using floating-point numbers. #[cfg(feature = "alloc")] @@ -168,7 +221,21 @@ impl SignedAmount { SignedAmount::from_str_in(&value.to_string(), denom) } - /// Constructs a new object that implements [`fmt::Display`] using specified denomination. + /// Constructs a new object that implements [`fmt::Display`] in the given [`Denomination`]. + /// + /// This function is useful if you do not wish to allocate. See also [`Self::to_string_in`]. + /// + /// # Examples + /// + /// ``` + /// # use bitcoin_units::amount::{SignedAmount, Denomination}; + /// # use std::fmt::Write; + /// let amount = SignedAmount::from_sat(10_000_000); + /// let mut output = String::new(); + /// write!(&mut output, "{}", amount.display_in(Denomination::Bitcoin))?; + /// assert_eq!(output, "0.1"); + /// # Ok::<(), std::fmt::Error>(()) + /// ``` #[must_use] pub fn display_in(self, denomination: Denomination) -> Display { Display { @@ -178,7 +245,8 @@ impl SignedAmount { } } - /// Constructs a new object that implements [`fmt::Display`] dynamically selecting denomination. + /// Constructs a new object that implements [`fmt::Display`] dynamically selecting + /// [`Denomination`]. /// /// This will use BTC for values greater than or equal to 1 BTC and satoshis otherwise. To /// avoid confusion the denomination is always shown. @@ -191,14 +259,30 @@ impl SignedAmount { } } - /// Returns a formatted string representing this [`SignedAmount`] in the given denomination. + /// Returns a formatted string representing this [`SignedAmount`] in the given [`Denomination`]. /// - /// Does not include the denomination. + /// Returned string does not include the denomination. + /// + /// # Examples + /// + /// ``` + /// # use bitcoin_units::amount::{SignedAmount, Denomination}; + /// let amount = SignedAmount::from_sat(10_000_000); + /// assert_eq!(amount.to_string_in(Denomination::Bitcoin), "0.1") + /// ``` #[cfg(feature = "alloc")] pub fn to_string_in(self, denom: Denomination) -> String { self.display_in(denom).to_string() } - /// Returns a formatted string representing this [`Amount`] in the given denomination, suffixed - /// with the abbreviation for the denomination. + /// Returns a formatted string representing this [`SignedAmount`] in the given [`Denomination`], + /// suffixed with the abbreviation for the denomination. + /// + /// # Examples + /// + /// ``` + /// # use bitcoin_units::amount::{SignedAmount, Denomination}; + /// let amount = SignedAmount::from_sat(10_000_000); + /// assert_eq!(amount.to_string_with_denomination(Denomination::Bitcoin), "0.1 BTC") + /// ``` #[cfg(feature = "alloc")] pub fn to_string_with_denomination(self, denom: Denomination) -> String { self.display_in(denom).show_denomination().to_string() @@ -206,7 +290,7 @@ impl SignedAmount { // Some arithmetic that doesn't fit in [`core::ops`] traits. - /// Get the absolute value of this [`SignedAmount`]. + /// Gets the absolute value of this [`SignedAmount`]. #[must_use] pub fn abs(self) -> SignedAmount { SignedAmount(self.0.abs()) } @@ -238,7 +322,7 @@ impl SignedAmount { /// /// Consider using `unsigned_abs` which is often more practical. /// - /// Returns [`None`] if overflow occurred. (`self == MIN`) + /// Returns [`None`] if overflow occurred. (`self == i64::MIN`) #[must_use] pub const fn checked_abs(self) -> Option { // No `map()` in const context. @@ -250,7 +334,7 @@ impl SignedAmount { /// Checked addition. /// - /// Returns [`None`] if overflow occurred. + /// Returns [`None`] if the sum is above [`SignedAmount::MAX`] or below [`SignedAmount::MIN`]. #[must_use] pub const fn checked_add(self, rhs: SignedAmount) -> Option { // No `map()` in const context. @@ -262,7 +346,8 @@ impl SignedAmount { /// Checked subtraction. /// - /// Returns [`None`] if overflow occurred. + /// Returns [`None`] if the difference is above [`SignedAmount::MAX`] or below + /// [`SignedAmount::MIN`]. #[must_use] pub const fn checked_sub(self, rhs: SignedAmount) -> Option { // No `map()` in const context. @@ -274,7 +359,8 @@ impl SignedAmount { /// Checked multiplication. /// - /// Returns [`None`] if overflow occurred. + /// Returns [`None`] if the product is above [`SignedAmount::MAX`] or below + /// [`SignedAmount::MIN`]. #[must_use] pub const fn checked_mul(self, rhs: i64) -> Option { // No `map()` in const context. @@ -345,6 +431,10 @@ impl SignedAmount { } /// Converts to an unsigned amount. + /// + /// # Errors + /// + /// If the amount is negative. pub fn to_unsigned(self) -> Result { if self.is_negative() { Err(OutOfRangeError::negative()) diff --git a/units/src/amount/unsigned.rs b/units/src/amount/unsigned.rs index be18ea8f2..49edb71be 100644 --- a/units/src/amount/unsigned.rs +++ b/units/src/amount/unsigned.rs @@ -81,6 +81,13 @@ impl Amount { pub const fn from_sat(satoshi: u64) -> Amount { Amount(satoshi) } /// Gets the number of satoshis in this [`Amount`]. + /// + /// # Examples + /// + /// ``` + /// # use bitcoin_units::Amount; + /// assert_eq!(Amount::ONE_BTC.to_sat(), 100_000_000); + /// ``` pub const fn to_sat(self) -> u64 { self.0 } /// Converts from a value expressing a decimal number of bitcoin to an [`Amount`]. @@ -90,6 +97,14 @@ impl Amount { /// If the amount is too big, too precise or negative. /// /// Please be aware of the risk of using floating-point numbers. + /// + /// # Examples + /// + /// ``` + /// # use bitcoin_units::Amount; + /// let amount = Amount::from_btc(0.01).expect("we know 0.01 is valid"); + /// assert_eq!(amount.to_sat(), 1_000_000); + /// ``` #[cfg(feature = "alloc")] pub fn from_btc(btc: f64) -> Result { Amount::from_float_in(btc, Denomination::Bitcoin) @@ -199,8 +214,7 @@ impl Amount { #[cfg(feature = "alloc")] pub fn to_btc(self) -> f64 { self.to_float_in(Denomination::Bitcoin) } - /// Converts this [`Amount`] in floating-point notation in the given - /// [`Denomination`]. + /// Converts this [`Amount`] in floating-point notation in the given [`Denomination`]. /// /// # Errors /// @@ -218,6 +232,20 @@ impl Amount { } /// Constructs a new object that implements [`fmt::Display`] in the given [`Denomination`]. + /// + /// This function is useful if you do not wish to allocate. See also [`Self::to_string_in`]. + /// + /// # Examples + /// + /// ``` + /// # use bitcoin_units::amount::{Amount, Denomination}; + /// # use std::fmt::Write; + /// let amount = Amount::from_sat(10_000_000); + /// let mut output = String::new(); + /// write!(&mut output, "{}", amount.display_in(Denomination::Bitcoin))?; + /// assert_eq!(output, "0.1"); + /// # Ok::<(), std::fmt::Error>(()) + /// ``` #[must_use] pub fn display_in(self, denomination: Denomination) -> Display { Display { @@ -326,7 +354,7 @@ impl Amount { /// /// Be aware that integer division loses the remainder if no exact division /// can be made. This method rounds up ensuring the transaction fee-rate is - /// sufficient. See also [`Amount::checked_div_by_weight_floor`]. + /// sufficient. See also [`Self::checked_div_by_weight_floor`]. /// /// Returns [`None`] if overflow occurred. /// @@ -359,7 +387,7 @@ impl Amount { /// Checked weight floor division. /// /// Be aware that integer division loses the remainder if no exact division - /// can be made. See also [`Amount::checked_div_by_weight_ceil`]. + /// can be made. See also [`Self::checked_div_by_weight_ceil`]. /// /// Returns [`None`] if overflow occurred. #[cfg(feature = "alloc")]