#![cfg_attr(not(any(test, feature = "std")), no_std)]
#![cfg_attr(
not(test),
deny(
clippy::indexing_slicing,
clippy::unwrap_used,
clippy::expect_used,
clippy::panic,
clippy::exhaustive_structs,
clippy::exhaustive_enums,
// TODO(#2266): enable missing_debug_implementations,
)
)]
#![warn(missing_docs)]
extern crate alloc;
mod error;
mod operands;
pub mod provider;
pub mod rules;
use core::cmp::{Ord, PartialOrd};
pub use error::PluralsError;
use icu_provider::prelude::*;
pub use operands::PluralOperands;
use provider::CardinalV1Marker;
use provider::ErasedPluralRulesV1Marker;
use provider::OrdinalV1Marker;
use rules::runtime::test_rule;
#[doc(inline)]
pub use PluralsError as Error;
#[derive(Debug, PartialEq, Eq, Clone, Copy, Hash)]
#[non_exhaustive]
pub enum PluralRuleType {
Cardinal,
Ordinal,
}
#[derive(Debug, PartialEq, Eq, Clone, Copy, Hash, Ord, PartialOrd)]
#[cfg_attr(feature = "datagen", derive(serde::Serialize))]
#[cfg_attr(feature = "serde", derive(serde::Deserialize))]
#[allow(clippy::exhaustive_enums)] pub enum PluralCategory {
Zero,
One,
Two,
Few,
Many,
Other,
}
impl PluralCategory {
pub fn all() -> impl ExactSizeIterator<Item = Self> {
[
Self::Few,
Self::Many,
Self::One,
Self::Other,
Self::Two,
Self::Zero,
]
.iter()
.copied()
}
pub fn get_for_cldr_string(category: &str) -> Option<PluralCategory> {
Self::get_for_cldr_bytes(category.as_bytes())
}
pub fn get_for_cldr_bytes(category: &[u8]) -> Option<PluralCategory> {
match category {
b"zero" => Some(PluralCategory::Zero),
b"one" => Some(PluralCategory::One),
b"two" => Some(PluralCategory::Two),
b"few" => Some(PluralCategory::Few),
b"many" => Some(PluralCategory::Many),
b"other" => Some(PluralCategory::Other),
_ => None,
}
}
}
pub struct PluralRules(DataPayload<ErasedPluralRulesV1Marker>);
impl PluralRules {
pub fn try_new_unstable<D>(
data_provider: &D,
locale: &DataLocale,
rule_type: PluralRuleType,
) -> Result<Self, PluralsError>
where
D: DataProvider<CardinalV1Marker> + DataProvider<OrdinalV1Marker> + ?Sized,
{
match rule_type {
PluralRuleType::Cardinal => Self::try_new_cardinal_unstable(data_provider, locale),
PluralRuleType::Ordinal => Self::try_new_ordinal_unstable(data_provider, locale),
}
}
icu_provider::gen_any_buffer_constructors!(
locale: include,
rule_type: PluralRuleType,
error: PluralsError
);
pub fn try_new_cardinal_unstable<D>(
data_provider: &D,
locale: &DataLocale,
) -> Result<Self, PluralsError>
where
D: DataProvider<CardinalV1Marker> + ?Sized,
{
Ok(Self(
data_provider
.load(DataRequest {
locale,
metadata: Default::default(),
})?
.take_payload()?
.cast(),
))
}
icu_provider::gen_any_buffer_constructors!(
locale: include,
options: skip,
error: PluralsError,
functions: [
Self::try_new_cardinal_unstable,
try_new_cardinal_with_any_provider,
try_new_cardinal_with_buffer_provider
]
);
pub fn try_new_ordinal_unstable<D>(
data_provider: &D,
locale: &DataLocale,
) -> Result<Self, PluralsError>
where
D: DataProvider<OrdinalV1Marker> + ?Sized,
{
Ok(Self(
data_provider
.load(DataRequest {
locale,
metadata: Default::default(),
})?
.take_payload()?
.cast(),
))
}
icu_provider::gen_any_buffer_constructors!(
locale: include,
options: skip,
error: PluralsError,
functions: [
Self::try_new_ordinal_unstable,
try_new_ordinal_with_any_provider,
try_new_ordinal_with_buffer_provider
]
);
pub fn category_for<I: Into<PluralOperands>>(&self, input: I) -> PluralCategory {
let rules = self.0.get();
let input = input.into();
macro_rules! test_rule {
($rule:ident, $cat:ident) => {
rules
.$rule
.as_ref()
.and_then(|r| test_rule(r, &input).then(|| PluralCategory::$cat))
};
}
test_rule!(zero, Zero)
.or_else(|| test_rule!(one, One))
.or_else(|| test_rule!(two, Two))
.or_else(|| test_rule!(few, Few))
.or_else(|| test_rule!(many, Many))
.unwrap_or(PluralCategory::Other)
}
pub fn categories(&self) -> impl Iterator<Item = PluralCategory> + '_ {
let rules = self.0.get();
macro_rules! test_rule {
($rule:ident, $cat:ident) => {
rules
.$rule
.as_ref()
.map(|_| PluralCategory::$cat)
.into_iter()
};
}
test_rule!(zero, Zero)
.chain(test_rule!(one, One))
.chain(test_rule!(two, Two))
.chain(test_rule!(few, Few))
.chain(test_rule!(many, Many))
.chain(Some(PluralCategory::Other).into_iter())
}
}