Skip to content

Commit

Permalink
Add impl From<&CompactDecimal> for PluralOperands (#4828)
Browse files Browse the repository at this point in the history
(cherry picked from commit 782a01a)
  • Loading branch information
sffc committed Jul 10, 2024
1 parent 694553a commit d83c4df
Show file tree
Hide file tree
Showing 8 changed files with 84 additions and 21 deletions.
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,9 @@
- `[email protected]`, `[email protected]`
- A full fix also needs `[email protected]`,`[email protected]`

- Upgrade `icu_compactdecimal` to use `u8` for compact exponent (https://github.com/unicode-org/icu4x/pull/4828)
- `[email protected]`


## icu4x 1.4 (Nov 16, 2023)

Expand Down
79 changes: 69 additions & 10 deletions components/plurals/src/operands.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ use core::isize;
use core::num::ParseIntError;
use core::str::FromStr;
use displaydoc::Display;
use fixed_decimal::FixedDecimal;
use fixed_decimal::{CompactDecimal, FixedDecimal};

/// A full plural operands representation of a number. See [CLDR Plural Rules](http://unicode.org/reports/tr35/tr35-numbers.html#Language_Plural_Rules) for complete operands description.
/// Plural operands in compliance with [CLDR Plural Rules](http://unicode.org/reports/tr35/tr35-numbers.html#Language_Plural_Rules).
Expand Down Expand Up @@ -235,25 +235,25 @@ macro_rules! impl_signed_integer_type {
impl_integer_type!(u8 u16 u32 u64 u128 usize);
impl_signed_integer_type!(i8 i16 i32 i64 i128 isize);

impl From<&FixedDecimal> for PluralOperands {
/// Converts a [`fixed_decimal::FixedDecimal`] to [`PluralOperands`]. Retains at most 18
/// digits each from the integer and fraction parts.
fn from(dec: &FixedDecimal) -> Self {
impl PluralOperands {
fn from_significand_and_exponent(dec: &FixedDecimal, exp: u8) -> PluralOperands {
let exp_i16 = i16::from(exp);

let mag_range = dec.magnitude_range();
let mag_high = core::cmp::min(17, *mag_range.end());
let mag_low = core::cmp::max(-18, *mag_range.start());
let mag_high = core::cmp::min(17, *mag_range.end() + exp_i16);
let mag_low = core::cmp::max(-18, *mag_range.start() + exp_i16);

let mut i: u64 = 0;
for magnitude in (0..=mag_high).rev() {
i *= 10;
i += dec.digit_at(magnitude) as u64;
i += dec.digit_at(magnitude - exp_i16) as u64;
}

let mut f: u64 = 0;
let mut t: u64 = 0;
let mut w: usize = 0;
for magnitude in (mag_low..=-1).rev() {
let digit = dec.digit_at(magnitude) as u64;
let digit = dec.digit_at(magnitude - exp_i16) as u64;
f *= 10;
f += digit;
if digit != 0 {
Expand All @@ -268,7 +268,66 @@ impl From<&FixedDecimal> for PluralOperands {
w,
f,
t,
c: 0,
c: usize::from(exp),
}
}
}

impl From<&FixedDecimal> for PluralOperands {
/// Converts a [`fixed_decimal::FixedDecimal`] to [`PluralOperands`]. Retains at most 18
/// digits each from the integer and fraction parts.
fn from(dec: &FixedDecimal) -> Self {
Self::from_significand_and_exponent(dec, 0)
}
}

impl From<&CompactDecimal> for PluralOperands {
/// Converts a [`fixed_decimal::CompactDecimal`] to [`PluralOperands`]. Retains at most 18
/// digits each from the integer and fraction parts.
///
/// # Examples
///
/// ```
/// use fixed_decimal::CompactDecimal;
/// use fixed_decimal::FixedDecimal;
/// use icu::locid::locale;
/// use icu::plurals::rules::RawPluralOperands;
/// use icu::plurals::PluralCategory;
/// use icu::plurals::PluralOperands;
/// use icu::plurals::PluralRules;
///
/// let fixed_decimal = "1000000.20".parse::<FixedDecimal>().unwrap();
/// let compact_decimal = "1.00000020c6".parse::<CompactDecimal>().unwrap();
///
/// assert_eq!(
/// PluralOperands::from(RawPluralOperands {
/// i: 1000000,
/// v: 2,
/// w: 1,
/// f: 20,
/// t: 2,
/// c: 0,
/// }),
/// PluralOperands::from(&fixed_decimal)
/// );
///
/// assert_eq!(
/// PluralOperands::from(RawPluralOperands {
/// i: 1000000,
/// v: 2,
/// w: 1,
/// f: 20,
/// t: 2,
/// c: 6,
/// }),
/// PluralOperands::from(&compact_decimal)
/// );
///
/// let rules = PluralRules::try_new_cardinal(&locale!("fr").into()).unwrap();
/// assert_eq!(rules.category_for(&fixed_decimal), PluralCategory::Other);
/// assert_eq!(rules.category_for(&compact_decimal), PluralCategory::Many);
/// ```
fn from(compact: &CompactDecimal) -> Self {
Self::from_significand_and_exponent(compact.significand(), compact.exponent())
}
}
2 changes: 1 addition & 1 deletion docs/tutorials/crates/baked/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ impl_data_provider!(BakedProvider);
fn main() {
let rules = PluralRules::try_new_cardinal_unstable(&BakedProvider, &locale!("ru").into())
.expect("locale 'ru' should be present in the baked data");
let result = rules.category_for(&3.into());
let result = rules.category_for(3);
assert_eq!(result, PluralCategory::Few);
println!("{:?}", result);
}
2 changes: 1 addition & 1 deletion docs/tutorials/crates/custom_compiled/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ use icu::plurals::PluralRules;
fn main() {
let rules = PluralRules::try_new_cardinal(&locale!("ru").into())
.expect("locale 'ru' should be present in the compiled data");
let result = rules.category_for(&3.into());
let result = rules.category_for(3);
assert_eq!(result, PluralCategory::Few);
println!("{result:?}");
}
2 changes: 1 addition & 1 deletion docs/tutorials/crates/default/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ use icu::plurals::PluralRules;
fn main() {
let rules = PluralRules::try_new_cardinal(&locale!("ru").into())
.expect("locale 'ru' should be present in the compiled data");
let result = rules.category_for(&3.into());
let result = rules.category_for(3);
assert_eq!(result, PluralCategory::Few);
println!("{result:?}");
}
7 changes: 4 additions & 3 deletions experimental/compactdecimal/src/compactdecimal.rs
Original file line number Diff line number Diff line change
Expand Up @@ -630,14 +630,15 @@ impl CompactDecimalFormatter {
&'l self,
value: &'l CompactDecimal,
) -> Result<FormattedCompactDecimal<'l>, CompactDecimalError> {
let log10_type = value.significand().nonzero_magnitude_start() + value.exponent();
let log10_type =
value.significand().nonzero_magnitude_start() + i16::from(value.exponent());

let (plural_map, expected_exponent) =
self.plural_map_and_exponent_for_magnitude(log10_type);
if value.exponent() != i16::from(expected_exponent) {
if value.exponent() != expected_exponent {
return Err(CompactDecimalError::Exponent {
actual: value.exponent(),
expected: i16::from(expected_exponent),
expected: expected_exponent,
log10_type,
});
}
Expand Down
4 changes: 2 additions & 2 deletions experimental/compactdecimal/src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -32,9 +32,9 @@ pub enum CompactDecimalError {
#[displaydoc("Expected compact exponent {expected} for 10^{log10_type}, got {actual}")]
Exponent {
/// The compact decimal exponent passed to the formatter.
actual: i16,
actual: u8,
/// The appropriate compact decimal exponent for a number of the given magnitude.
expected: i16,
expected: u8,
/// The magnitude of the number being formatted.
log10_type: i16,
},
Expand Down
6 changes: 3 additions & 3 deletions utils/fixed_decimal/src/compact.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,15 +22,15 @@ use crate::FixedDecimal;
#[derive(Debug, Clone, PartialEq)]
pub struct CompactDecimal {
significand: FixedDecimal,
exponent: i16,
exponent: u8,
}

impl CompactDecimal {
/// Constructs a [`CompactDecimal`] from its significand and exponent.
pub fn from_significand_and_exponent(significand: FixedDecimal, exponent: u8) -> Self {
Self {
significand,
exponent: exponent.into(),
exponent,
}
}

Expand Down Expand Up @@ -75,7 +75,7 @@ impl CompactDecimal {
/// assert_eq!(CompactDecimal::from_str("+1.20c6").unwrap().exponent(), 6);
/// assert_eq!(CompactDecimal::from_str("1729").unwrap().exponent(), 0);
/// ```
pub fn exponent(&self) -> i16 {
pub fn exponent(&self) -> u8 {
self.exponent
}
}
Expand Down

0 comments on commit d83c4df

Please sign in to comment.