Skip to content

Commit

Permalink
Add impl From<&CompactDecimal> for PluralOperands (#4828)
Browse files Browse the repository at this point in the history
  • Loading branch information
sffc committed May 23, 2024
1 parent d938156 commit 782a01a
Show file tree
Hide file tree
Showing 8 changed files with 85 additions and 21 deletions.
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@
- Added `total_cmp` functions to `Locale` and other types to make them easier to use in `BTreeSet` (https://github.com/unicode-org/icu4x/pull/4608)
- `icu_locid_transform`
- Add `LocaleExpander::minimize_favor_script` (https://github.com/unicode-org/icu4x/pull/4752)
- `icu_plurals`
- Added support for `CompactDecimal` (https://github.com/unicode-org/icu4x/pull/4828)
- `icu_properties`
- Add `Aran` script code (https://github.com/unicode-org/icu4x/pull/4426)
- Mark additional constructors as `const` (https://github.com/unicode-org/icu4x/pull/4584, https://github.com/unicode-org/icu4x/pull/4574)
Expand Down Expand Up @@ -54,6 +56,8 @@
- Deprecate `Hebrew::new_always_precomputing()`, `Date::try_new_hebrew_date_with_calendar()`, `DateTime::try_new_hebrew_datetime_with_calendar()`. The new implementation of the Hebrew calendar is faster and we do not need APIs for precomputation. (https://github.com/unicode-org/icu4x/pulls/4532)
- `databake`
- Add `impl Bake for PhantomData<T>` (https://github.com/unicode-org/icu4x/pull/4663)
- `fixed_decimal`
- Changed type of compact exponent from `i16` to `u8` (https://github.com/unicode-org/icu4x/pull/4828)
- `litemap`
- Add `impl IntoIterator for LiteMap` by splitting `StoreIterableMut` trait (https://github.com/unicode-org/icu4x/pull/4359)
- `yoke`
Expand Down
7 changes: 4 additions & 3 deletions components/experimental/src/compactdecimal/compactdecimal.rs
Original file line number Diff line number Diff line change
Expand Up @@ -629,14 +629,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 components/experimental/src/compactdecimal/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
79 changes: 69 additions & 10 deletions components/plurals/src/operands.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
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 @@ -234,25 +234,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 @@ -267,7 +267,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 tutorials/rust/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 tutorials/rust/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 tutorials/rust/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:?}");
}
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 @@ -74,7 +74,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 782a01a

Please sign in to comment.