use crate::operands::PluralOperands;
use crate::provider::PluralRuleStringsV1;
use crate::rules;
use crate::rules::ast;
use crate::{PluralCategory, PluralRulesError};
use alloc::borrow::Cow;
use core::convert::TryInto;
#[derive(Default, Debug)]
pub struct PluralRuleList {
zero: Option<ast::Condition>,
one: Option<ast::Condition>,
two: Option<ast::Condition>,
few: Option<ast::Condition>,
many: Option<ast::Condition>,
}
impl PluralRuleList {
fn has_rules_for(&self, category: PluralCategory) -> bool {
match category {
PluralCategory::Zero => self.zero.is_some(),
PluralCategory::One => self.one.is_some(),
PluralCategory::Two => self.two.is_some(),
PluralCategory::Few => self.few.is_some(),
PluralCategory::Many => self.many.is_some(),
PluralCategory::Other => true,
}
}
fn get(&self, category: PluralCategory) -> Option<&ast::Condition> {
match category {
PluralCategory::Zero => self.zero.as_ref(),
PluralCategory::One => self.one.as_ref(),
PluralCategory::Two => self.two.as_ref(),
PluralCategory::Few => self.few.as_ref(),
PluralCategory::Many => self.many.as_ref(),
PluralCategory::Other => None,
}
}
}
fn parse_rule(input: &Option<Cow<str>>) -> Result<Option<ast::Condition>, PluralRulesError> {
Ok(if let Some(input) = input {
Some(rules::parse_condition((input).as_bytes())?)
} else {
None
})
}
impl<'data> TryInto<PluralRuleList> for &PluralRuleStringsV1<'data> {
type Error = PluralRulesError;
fn try_into(self) -> Result<PluralRuleList, Self::Error> {
Ok(PluralRuleList {
zero: parse_rule(&self.zero)?,
one: parse_rule(&self.one)?,
two: parse_rule(&self.two)?,
few: parse_rule(&self.few)?,
many: parse_rule(&self.many)?,
})
}
}
pub enum RulesSelector {
Conditions(PluralRuleList),
}
impl RulesSelector {
pub fn select(&self, operands: &PluralOperands) -> PluralCategory {
match self {
Self::Conditions(conditions) => PluralCategory::all()
.find_map(|category| {
conditions
.get(*category)
.filter(|cond| rules::test_condition(cond, operands))
.map(|_| *category)
})
.unwrap_or(PluralCategory::Other),
}
}
pub fn categories(&self) -> impl Iterator<Item = &'static PluralCategory> + '_ {
match self {
Self::Conditions(conditions) => {
PluralCategory::all().filter(move |&category| conditions.has_rules_for(*category))
}
}
}
}
impl From<PluralRuleList> for RulesSelector {
fn from(input: PluralRuleList) -> Self {
Self::Conditions(input)
}
}