Skip to content

Commit

Permalink
Respect precision while formatting Amount
Browse files Browse the repository at this point in the history
All characters beyond the needed precision are truncated

In the case of a SignedAmount the default precision is now 8
just like the Amount

Just like the existing code, no width is added if there exists
fractional values exist just like the existing code works.

Tests have been improved to handle precision

Resolves: #2136
  • Loading branch information
448-OG committed Apr 13, 2024
1 parent 52080a0 commit 93037b1
Showing 1 changed file with 37 additions and 23 deletions.
60 changes: 37 additions & 23 deletions units/src/amount.rs
Expand Up @@ -670,7 +670,7 @@ fn split_amount_and_denomination(s: &str) -> Result<(&str, Denomination), ParseE
}

/// Options given by `fmt::Formatter`
struct FormatOptions {
pub struct FormatOptions {
fill: char,
align: Option<fmt::Alignment>,
width: Option<usize>,
Expand Down Expand Up @@ -821,9 +821,17 @@ fn fmt_satoshi_in(
if total_decimals > 0 {
write!(f, ".")?;
}
if norm_nb_decimals > 0 {

if let Some(f_precision) = options.precision {
if f_precision < norm_nb_decimals && norm_nb_decimals > 0 {
write!(f, "{:0width$}", 0, width = f_precision)?;
} else if norm_nb_decimals > 0 {
write!(f, "{:0width$}", num_after_decimal_point, width = norm_nb_decimals)?;
}
} else if norm_nb_decimals > 0 {
write!(f, "{:0width$}", num_after_decimal_point, width = norm_nb_decimals)?;
}

repeat_char(f, '0', trailing_decimal_zeros)?;

if show_denom {
Expand Down Expand Up @@ -1349,8 +1357,8 @@ impl SignedAmount {
///
/// Does not include the denomination.
#[rustfmt::skip]
pub fn fmt_value_in(self, f: &mut dyn fmt::Write, denom: Denomination) -> fmt::Result {
fmt_satoshi_in(self.unsigned_abs().to_sat(), self.is_negative(), f, denom, false, FormatOptions::default())
pub fn fmt_value_in(self, f: &mut dyn fmt::Write, denom: Denomination, options: FormatOptions) -> fmt::Result {
fmt_satoshi_in(self.unsigned_abs().to_sat(), self.is_negative(), f, denom, false, options)
}

/// Get a string number of this [SignedAmount] in the given denomination.
Expand All @@ -1359,7 +1367,7 @@ impl SignedAmount {
#[cfg(feature = "alloc")]
pub fn to_string_in(self, denom: Denomination) -> String {
let mut buf = String::new();
self.fmt_value_in(&mut buf, denom).unwrap();
self.fmt_value_in(&mut buf, denom, FormatOptions::default()).unwrap();
buf
}

Expand All @@ -1368,7 +1376,7 @@ impl SignedAmount {
#[cfg(feature = "alloc")]
pub fn to_string_with_denomination(self, denom: Denomination) -> String {
let mut buf = String::new();
self.fmt_value_in(&mut buf, denom).unwrap();
self.fmt_value_in(&mut buf, denom, FormatOptions::default()).unwrap();
write!(buf, " {}", denom).unwrap();
buf
}
Expand Down Expand Up @@ -1476,7 +1484,10 @@ impl fmt::Debug for SignedAmount {
// Just using Bitcoin denominated string.
impl fmt::Display for SignedAmount {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
self.fmt_value_in(f, Denomination::Bitcoin)?;
let mut format_options = FormatOptions::default();
format_options.precision.replace(f.precision().unwrap_or(8));
self.fmt_value_in(f, Denomination::Bitcoin, format_options)?;

write!(f, " {}", Denomination::Bitcoin)
}
}
Expand Down Expand Up @@ -2415,10 +2426,10 @@ mod tests {
btc_check_fmt_non_negative_6, 1, "{}", "0.00000001";
btc_check_fmt_non_negative_7, 1, "{:2}", "0.00000001";
btc_check_fmt_non_negative_8, 1, "{:02}", "0.00000001";
btc_check_fmt_non_negative_9, 1, "{:.1}", "0.00000001";
btc_check_fmt_non_negative_9, 1, "{:.1}", "0.0";
btc_check_fmt_non_negative_10, 1, "{:11}", " 0.00000001";
btc_check_fmt_non_negative_11, 1, "{:11.1}", " 0.00000001";
btc_check_fmt_non_negative_12, 1, "{:011.1}", "00.00000001";
btc_check_fmt_non_negative_11, 1, "{:11.1}", " 0.0";
btc_check_fmt_non_negative_12, 1, "{:011.1}", "00.0";
btc_check_fmt_non_negative_13, 1, "{:.9}", "0.000000010";
btc_check_fmt_non_negative_14, 1, "{:11.9}", "0.000000010";
btc_check_fmt_non_negative_15, 1, "{:011.9}", "0.000000010";
Expand All @@ -2433,7 +2444,7 @@ mod tests {
btc_check_fmt_non_negative_24, 110_000_000, "{}", "1.1";
btc_check_fmt_non_negative_25, 100_000_001, "{}", "1.00000001";
btc_check_fmt_non_negative_26, 100_000_001, "{:1}", "1.00000001";
btc_check_fmt_non_negative_27, 100_000_001, "{:.1}", "1.00000001";
btc_check_fmt_non_negative_27, 100_000_001, "{:.1}", "1.0";
btc_check_fmt_non_negative_28, 100_000_001, "{:10}", "1.00000001";
btc_check_fmt_non_negative_29, 100_000_001, "{:11}", " 1.00000001";
btc_check_fmt_non_negative_30, 100_000_001, "{:011}", "01.00000001";
Expand Down Expand Up @@ -2465,7 +2476,7 @@ mod tests {

check_format_non_negative_show_denom! {
Bitcoin, " BTC";
btc_check_fmt_non_negative_show_denom_0, 1, "{:14.1}", "0.00000001";
btc_check_fmt_non_negative_show_denom_0, 1, "{:14.1}", "0.0";
btc_check_fmt_non_negative_show_denom_1, 1, "{:14.8}", "0.00000001";
btc_check_fmt_non_negative_show_denom_2, 1, "{:15}", " 0.00000001";
btc_check_fmt_non_negative_show_denom_3, 1, "{:015}", "00.00000001";
Expand Down Expand Up @@ -2940,18 +2951,21 @@ mod tests {
assert_eq!(format!("{}", Amount::ONE_BTC), "1 BTC");
assert_eq!(format!("{}", Amount::from_sat(1)), "0.00000001 BTC");
assert_eq!(format!("{}", Amount::from_sat(10)), "0.00000010 BTC");
assert_eq!(format!("{:.2}", Amount::from_sat(10)), "0.0000001 BTC");
assert_eq!(format!("{:.2}", Amount::from_sat(100)), "0.000001 BTC");
assert_eq!(format!("{:.2}", Amount::from_sat(1000)), "0.00001 BTC");
assert_eq!(format!("{:.2}", Amount::from_sat(10_000)), "0.0001 BTC");
assert_eq!(format!("{:.2}", Amount::from_sat(100_000)), "0.001 BTC");
assert_eq!(format!("{:.2}", Amount::from_sat(1_000_000)), "0.01 BTC");
assert_eq!(format!("{:.2}", Amount::from_sat(10_000_000)), "0.10 BTC");
assert_eq!(format!("{:.1}", Amount::from_sat(10)), "0.0 BTC");
assert_eq!(format!("{:.2}", Amount::from_sat(10)), "0.00 BTC");
assert_eq!(format!("{:.3}", Amount::from_sat(10)), "0.000 BTC");
assert_eq!(format!("{:.4}", Amount::from_sat(10)), "0.0000 BTC");
assert_eq!(format!("{:.5}", Amount::from_sat(10)), "0.00000 BTC");
assert_eq!(format!("{:.6}", Amount::from_sat(10)), "0.000000 BTC");
assert_eq!(format!("{:.7}", Amount::from_sat(10)), "0.0000001 BTC");
assert_eq!(format!("{:.8}", Amount::from_sat(10)), "0.00000010 BTC");
assert_eq!(format!("{:.9}", Amount::from_sat(10)), "0.000000100 BTC");
assert_eq!(format!("{:.1}", Amount::from_sat(100_000_000)), "1.0 BTC");
assert_eq!(format!("{:.2}", Amount::from_sat(100_000_000)), "1.00 BTC");
assert_eq!(format!("{}", Amount::from_sat(100_000_000)), "1 BTC");
assert_eq!(format!("{}", Amount::from_sat(40_000_000_000)), "400 BTC");
assert_eq!(format!("{:.10}", Amount::from_sat(100_000_000)), "1.0000000000 BTC");
assert_eq!(format!("{}", Amount::from_sat(400_000_000_000_010)), "4000000.00000010 BTC");
assert_eq!(format!("{}", Amount::from_sat(400_000_000_000_000)), "4000000 BTC");
assert_eq!(format!("{}", Amount::from_sat(40_000_000_001)), "400.00000001 BTC");
assert_eq!(format!("{}", Amount::from_sat(40_000_000_010)), "400.00000010 BTC");
assert_eq!(format!("{:.7}", Amount::from_sat(40_000_000_010)), "400.0000001 BTC");
assert_eq!(format!("{:.1}", Amount::from_sat(40_000_000_001)), "400.0 BTC");
}
}

0 comments on commit 93037b1

Please sign in to comment.