Skip to content

Commit

Permalink
Add format_fixed_decimal to CompactDecimalFormatter
Browse files Browse the repository at this point in the history
  • Loading branch information
sffc committed Aug 26, 2023
1 parent bddf819 commit 60e900d
Show file tree
Hide file tree
Showing 2 changed files with 120 additions and 2 deletions.
96 changes: 94 additions & 2 deletions experimental/compactdecimal/src/compactdecimal.rs
Original file line number Diff line number Diff line change
Expand Up @@ -278,6 +278,9 @@ impl CompactDecimalFormatter {
/// 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;
Expand All @@ -295,8 +298,10 @@ impl CompactDecimalFormatter {
/// assert_writeable_eq!(short_english.format_i64(3_010_349), "3M");
/// assert_writeable_eq!(short_english.format_i64(-13_132), "-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;
Expand All @@ -315,9 +320,95 @@ impl CompactDecimalFormatter {
/// ```
pub fn format_i64(&self, value: i64) -> FormattedCompactDecimal<'_> {
let unrounded = FixedDecimal::from(value);
let log10_type = unrounded.nonzero_magnitude_start();
self.format_fixed_decimal(unrounded)
}

/// Formats a [`FixedDecimal`] by automatically scaling and rounding it.
///
/// The result may have a fractional digit only if it is compact and its
/// significand is less than 10. Trailing fractional 0s are omitted.
///
/// Because the FixedDecimal is mutated before formatting, this function
/// takes ownership of it.
///
/// # Examples
///
/// ```
/// use fixed_decimal::FixedDecimal;
/// 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_fixed_decimal(FixedDecimal::from(0)),
/// "0");
/// assert_writeable_eq!(
/// short_english.format_fixed_decimal(FixedDecimal::from(2)),
/// "2");
/// assert_writeable_eq!(
/// short_english.format_fixed_decimal(FixedDecimal::from(843)),
/// "843");
/// assert_writeable_eq!(
/// short_english.format_fixed_decimal(FixedDecimal::from(2207)),
/// "2.2K");
/// assert_writeable_eq!(
/// short_english.format_fixed_decimal(FixedDecimal::from(15127)),
/// "15K");
/// assert_writeable_eq!(
/// short_english.format_fixed_decimal(FixedDecimal::from(3010349)),
/// "3M");
/// assert_writeable_eq!(
/// short_english.format_fixed_decimal(FixedDecimal::from(-13132)),
/// "-13K");
///
/// // The sign display on the FixedDecimal is respected:
/// assert_writeable_eq!(
/// short_english.format_fixed_decimal(FixedDecimal::from(2500)
/// .with_sign_display(fixed_decimal::SignDisplay::ExceptZero)),
/// "+2.5K");
/// ```
///
/// The result is the nearest such compact number, with halfway cases-
/// rounded towards the number with an even least significant digit.
///
/// ```
/// # use fixed_decimal::FixedDecimal;
/// # 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_fixed_decimal("999499.99".parse().unwrap()),
/// "999K");
/// assert_writeable_eq!(
/// short_english.format_fixed_decimal("999500.00".parse().unwrap()),
/// "1M");
/// assert_writeable_eq!(
/// short_english.format_fixed_decimal("1650".parse().unwrap()),
/// "1.6K");
/// assert_writeable_eq!(
/// short_english.format_fixed_decimal("1750".parse().unwrap()),
/// "1.8K");
/// assert_writeable_eq!(
/// short_english.format_fixed_decimal("1950".parse().unwrap()),
/// "2K");
/// assert_writeable_eq!(
/// short_english.format_fixed_decimal("-1172700".parse().unwrap()),
/// "-1.2M");
/// ```
pub fn format_fixed_decimal(&self, value: FixedDecimal) -> FormattedCompactDecimal<'_> {
let log10_type = value.nonzero_magnitude_start();
let (mut plural_map, mut exponent) = self.plural_map_and_exponent_for_magnitude(log10_type);
let mut significand = unrounded.multiplied_pow10(-i16::from(exponent));
let mut significand = value.multiplied_pow10(-i16::from(exponent));
// If we have just one digit before the decimal point…
if significand.nonzero_magnitude_start() == 0 {
// …round to one fractional digit…
Expand Down Expand Up @@ -373,6 +464,7 @@ impl CompactDecimalFormatter {
/// be equal to `formatter.compact_exponent_for_magnitude(n.significand().nonzero_magnitude_start() + n.exponent())`.
///
/// # Examples
///
/// ```
/// # use icu_compactdecimal::CompactDecimalFormatter;
/// # use icu_locid::locale;
Expand Down
26 changes: 26 additions & 0 deletions experimental/compactdecimal/src/format.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,32 @@ pub struct FormattedCompactDecimal<'l> {
pub(crate) plural_map: Option<ZeroMap2dCursor<'l, 'l, i8, Count, PatternULE>>,
}

impl FormattedCompactDecimal<'_> {
/// Access the resolved [`CompactDecimal`] after formatting.
///
/// # Examples
///
/// ```
/// use fixed_decimal::FixedDecimal;
/// 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();
///
/// let formatted_compact_decimal = short_english.format_i64(2207);
///
/// assert_writeable_eq!(formatted_compact_decimal, "2.2K");
/// assert_eq!(formatted_compact_decimal.get_compact_decimal().to_string(), "2.2c3");
/// ```
pub fn get_compact_decimal(&self) -> &CompactDecimal {
&self.value
}
}

impl<'l> Writeable for FormattedCompactDecimal<'l> {
fn write_to<W>(&self, sink: &mut W) -> core::result::Result<(), core::fmt::Error>
where
Expand Down

0 comments on commit 60e900d

Please sign in to comment.