Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Redesign PluralRulesWithRanges #4272

Merged
merged 1 commit into from
Nov 11, 2023
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
136 changes: 77 additions & 59 deletions components/plurals/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -284,6 +284,12 @@ impl PluralCategory {
#[derive(Debug)]
pub struct PluralRules(DataPayload<ErasedPluralRulesV1Marker>);

impl AsRef<PluralRules> for PluralRules {
fn as_ref(&self) -> &PluralRules {
self
}
}

impl PluralRules {
icu_provider::gen_any_buffer_data_constructors!(
locale: include,
Expand Down Expand Up @@ -594,13 +600,13 @@ impl PluralRules {
/// [`Plural Category`]: PluralCategory
#[cfg(feature = "experimental")]
#[derive(Debug)]
pub struct PluralRulesWithRanges {
rules: PluralRules,
pub struct PluralRulesWithRanges<R> {
rules: R,
ranges: DataPayload<PluralRangesV1Marker>,
}

#[cfg(feature = "experimental")]
impl PluralRulesWithRanges {
impl PluralRulesWithRanges<PluralRules> {
icu_provider::gen_any_buffer_data_constructors!(
locale: include,
rule_type: PluralRuleType,
Expand Down Expand Up @@ -678,14 +684,8 @@ impl PluralRulesWithRanges {
locale: &DataLocale,
) -> Result<Self, PluralsError> {
let rules = PluralRules::try_new_cardinal_unstable(provider, locale)?;
let ranges = provider
.load(DataRequest {
locale,
metadata: Default::default(),
})?
.take_payload()?;

Ok(Self { rules, ranges })
PluralRulesWithRanges::try_new_with_rules_unstable(provider, locale, rules)
}

icu_provider::gen_any_buffer_data_constructors!(
Expand Down Expand Up @@ -729,6 +729,60 @@ impl PluralRulesWithRanges {
locale: &DataLocale,
) -> Result<Self, PluralsError> {
let rules = PluralRules::try_new_ordinal_unstable(provider, locale)?;

PluralRulesWithRanges::try_new_with_rules_unstable(provider, locale, rules)
}
}

#[cfg(feature = "experimental")]
impl<R> PluralRulesWithRanges<R>
where
R: AsRef<PluralRules>,
{
icu_provider::gen_any_buffer_data_constructors!(
locale: include,
rules: R,
error: PluralsError,
/// Constructs a new `PluralRulesWithRanges` for a given locale from an existing
/// `PluralRules` (either owned or as a reference) and compiled data.
///
/// # ⚠️ Warning
///
/// The provided `locale` **MUST** be the same as the locale provided to the constructor
/// of `rules`. Otherwise, [`Self::category_for_range`] will return incorrect results.
///
/// ✨ *Enabled with the `compiled_data` Cargo feature.*
///
/// [📚 Help choosing a constructor](icu_provider::constructors)
///
/// # Examples
///
/// ```
/// use icu::locid::locale;
/// use icu::plurals::{PluralRuleType, PluralRulesWithRanges, PluralRules};
///
/// let rules = PluralRules::try_new(&locale!("en").into(), PluralRuleType::Cardinal)
/// .expect("locale should be present");
///
/// let _ =
/// PluralRulesWithRanges::try_new_with_rules(&locale!("en").into(), rules)
/// .expect("locale should be present");
/// ```
functions: [
try_new_with_rules,
try_new_with_rules_with_any_provider,
try_new_with_rules_with_buffer_provider,
try_new_with_rules_unstable,
Self,
]
);

#[doc = icu_provider::gen_any_buffer_unstable_docs!(UNSTABLE, Self::try_new_with_rules)]
pub fn try_new_with_rules_unstable(
provider: &(impl DataProvider<PluralRangesV1Marker> + ?Sized),
locale: &DataLocale,
rules: R,
) -> Result<Self, PluralsError> {
let ranges = provider
.load(DataRequest {
locale,
Expand All @@ -739,61 +793,24 @@ impl PluralRulesWithRanges {
Ok(Self { rules, ranges })
}

/// Returns the [`Plural Category`] appropriate for the given number.
///
/// See [`PluralRules::category_for`] for more information.
/// Gets a reference to the inner `PluralRules`.
///
/// # Examples
///
/// ```
/// use icu::locid::locale;
/// use icu::plurals::{PluralCategory, PluralRuleType, PluralRulesWithRanges};
///
/// let pr = PluralRulesWithRanges::try_new(
/// &locale!("en").into(),
/// PluralRuleType::Cardinal,
/// )
/// .expect("locale should be present");
///
/// match pr.category_for(1_usize) {
/// PluralCategory::One => "One item",
/// PluralCategory::Other => "Many items",
/// _ => unreachable!(),
/// };
/// ```
/// use icu::plurals::{PluralCategory, PluralRulesWithRanges};
///
/// [`Plural Category`]: PluralCategory
pub fn category_for<I: Into<PluralOperands>>(&self, input: I) -> PluralCategory {
self.rules.category_for(input)
}

/// Returns all [`Plural Categories`] appropriate for a [`PluralRulesWithRanges`] object
/// based on the [`LanguageIdentifier`](icu::locid::{LanguageIdentifier}) and [`PluralRuleType`].
///
/// See [`PluralRules::categories`] for more information.
/// let ranges =
/// PluralRulesWithRanges::try_new_cardinal(&locale!("en").into())
/// .expect("locale should be present");
///
/// # Examples
/// let rules = ranges.rules();
///
/// assert_eq!(rules.category_for(1u8), PluralCategory::One);
/// ```
/// use icu::locid::locale;
/// use icu::plurals::{PluralCategory, PluralRuleType, PluralRulesWithRanges};
///
/// let pr = PluralRulesWithRanges::try_new(
/// &locale!("es").into(),
/// PluralRuleType::Cardinal,
/// )
/// .expect("locale should be present");
///
/// let mut categories = pr.categories();
/// assert_eq!(categories.next(), Some(PluralCategory::One));
/// assert_eq!(categories.next(), Some(PluralCategory::Many));
/// assert_eq!(categories.next(), Some(PluralCategory::Other));
/// assert_eq!(categories.next(), None);
/// ```
///
/// [`Plural Categories`]: PluralCategory
pub fn categories(&self) -> impl Iterator<Item = PluralCategory> + '_ {
self.rules.categories()
pub fn rules(&self) -> &PluralRules {
self.rules.as_ref()
}

/// Returns the [`Plural Category`] appropriate for a range.
Expand All @@ -816,7 +833,7 @@ impl PluralRulesWithRanges {
/// )
/// .expect("locale should be present");
/// let operands: PluralOperands =
/// "1.5".parse().expect("parsing to operands should succeed");
/// "0.5".parse().expect("parsing to operands should succeed");
/// let operands2 = PluralOperands::from(1_usize);
///
/// assert_eq!(
Expand All @@ -831,8 +848,9 @@ impl PluralRulesWithRanges {
start: S,
end: E,
) -> PluralCategory {
let start = self.rules.category_for(start);
let end = self.rules.category_for(end);
let rules = self.rules.as_ref();
let start = rules.category_for(start);
let end = rules.category_for(end);

self.resolve_range(start, end)
}
Expand Down