Skip to content

Commit

Permalink
Add format_f64 and other helpers
Browse files Browse the repository at this point in the history
  • Loading branch information
sffc committed Aug 26, 2023
1 parent 60e900d commit 2df9c58
Show file tree
Hide file tree
Showing 5 changed files with 136 additions and 57 deletions.
1 change: 1 addition & 0 deletions experimental/compactdecimal/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -46,3 +46,4 @@ std = ["fixed_decimal/std", "icu_decimal/std", "icu_plurals/std", "icu_provider/
serde = ["dep:serde", "zerovec/serde", "icu_decimal/serde", "icu_plurals/serde"]
datagen = ["std", "serde", "dep:databake", "zerovec/databake"]
compiled_data = ["dep:icu_compactdecimal_data", "dep:icu_locid_transform", "icu_decimal/compiled_data", "icu_plurals/compiled_data"]
ryu = ["fixed_decimal/ryu"]
76 changes: 68 additions & 8 deletions experimental/compactdecimal/src/compactdecimal.rs
Original file line number Diff line number Diff line change
Expand Up @@ -282,14 +282,15 @@ impl CompactDecimalFormatter {
/// # Examples
///
/// ```
/// # use icu_compactdecimal::CompactDecimalFormatter;
/// # use icu_locid::locale;
/// # use writeable::assert_writeable_eq;
/// #
/// # let short_english = CompactDecimalFormatter::try_new_short(
/// # &locale!("en").into(),
/// # Default::default(),
/// # ).unwrap();
/// use icu_compactdecimal::CompactDecimalFormatter;
/// use icu_locid::locale;
/// use writeable::assert_writeable_eq;
///
/// let short_english = CompactDecimalFormatter::try_new_short(
/// &locale!("en").into(),
/// Default::default(),
/// ).unwrap();
///
/// assert_writeable_eq!(short_english.format_i64(0), "0");
/// assert_writeable_eq!(short_english.format_i64(2), "2");
/// assert_writeable_eq!(short_english.format_i64(843), "843");
Expand Down Expand Up @@ -323,6 +324,65 @@ impl CompactDecimalFormatter {
self.format_fixed_decimal(unrounded)
}

/// Formats an integer in compact decimal notation using the default
/// precision settings.
///
/// The result may have a fractional digit only if it is compact and its
/// significand is less than 10. Trailing fractional 0s are omitted, and
/// a sign is shown only for negative values.
///
/// # Examples
///
/// ```
/// use icu_compactdecimal::CompactDecimalFormatter;
/// use icu_locid::locale;
/// use writeable::assert_writeable_eq;
///
/// let short_english = CompactDecimalFormatter::try_new_short(
/// &locale!("en").into(),
/// Default::default(),
/// ).unwrap();
///
/// assert_writeable_eq!(short_english.format_f64(0.0).unwrap(), "0");
/// assert_writeable_eq!(short_english.format_f64(2.0).unwrap(), "2");
/// assert_writeable_eq!(short_english.format_f64(843.0).unwrap(), "843");
/// assert_writeable_eq!(short_english.format_f64(2207.0).unwrap(), "2.2K");
/// assert_writeable_eq!(short_english.format_f64(15_127.0).unwrap(), "15K");
/// assert_writeable_eq!(short_english.format_f64(3_010_349.0).unwrap(), "3M");
/// assert_writeable_eq!(short_english.format_f64(-13_132.0).unwrap(), "-13K");
/// ```
///
/// The result is the nearest such compact number, with halfway cases-
/// rounded towards the number with an even least significant digit.
///
/// ```
/// # use icu_compactdecimal::CompactDecimalFormatter;
/// # use icu_locid::locale;
/// # use writeable::assert_writeable_eq;
/// #
/// # let short_english = CompactDecimalFormatter::try_new_short(
/// # &locale!("en").into(),
/// # Default::default(),
/// # ).unwrap();
/// assert_writeable_eq!(short_english.format_f64(999_499.99).unwrap(), "999K");
/// assert_writeable_eq!(short_english.format_f64(999_500.00).unwrap(), "1M");
/// assert_writeable_eq!(short_english.format_f64(1650.0).unwrap(), "1.6K");
/// assert_writeable_eq!(short_english.format_f64(1750.0).unwrap(), "1.8K");
/// assert_writeable_eq!(short_english.format_f64(1950.0).unwrap(), "2K");
/// assert_writeable_eq!(short_english.format_f64(-1_172_700.0).unwrap(), "-1.2M");
/// ```
#[cfg(feature = "ryu")]
pub fn format_f64(
&self,
value: f64,
) -> Result<FormattedCompactDecimal<'_>, CompactDecimalError> {
use fixed_decimal::FloatPrecision::Floating;
// NOTE: This first gets the shortest representation of the f64, which
// manifests as double rounding.
let partly_rounded = FixedDecimal::try_from_f64(value, Floating)?;
Ok(self.format_fixed_decimal(partly_rounded))
}

/// Formats a [`FixedDecimal`] by automatically scaling and rounding it.
///
/// The result may have a fractional digit only if it is compact and its
Expand Down
10 changes: 10 additions & 0 deletions experimental/compactdecimal/src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
// (online at: https://github.com/unicode-org/icu4x/blob/main/LICENSE ).

use displaydoc::Display;
use fixed_decimal::FixedDecimalError;
use icu_decimal::DecimalError;
use icu_plurals::PluralsError;
use icu_provider::DataError;
Expand All @@ -22,6 +23,9 @@ pub enum CompactDecimalError {
/// An error originating from [`FixedDecimalFormatter`](icu_decimal::FixedDecimalFormatter).
#[displaydoc("Error loading FixedDecimalFormatter: {0}")]
Decimal(DecimalError),
/// An error originating from [`FixedDecimal`](fixed_decimal::FixedDecimal).
#[displaydoc("Error creating FixedDecimal: {0}")]
FixedDecimal(FixedDecimalError),
/// An error due to a [`CompactDecimal`](fixed_decimal::CompactDecimal) with an
/// exponent inconsistent with the compact decimal data for the locale, e.g.,
/// when formatting 1c5 in English (US).
Expand Down Expand Up @@ -53,3 +57,9 @@ impl From<DecimalError> for CompactDecimalError {
CompactDecimalError::Decimal(e)
}
}

impl From<FixedDecimalError> for CompactDecimalError {
fn from(e: FixedDecimalError) -> Self {
CompactDecimalError::FixedDecimal(e)
}
}
Loading

0 comments on commit 2df9c58

Please sign in to comment.