pub mod operands;
#[cfg(not(tarpaulin_include))]
mod rules;
use std::convert::TryInto;
use unic_langid::LanguageIdentifier;
use crate::operands::PluralOperands;
use crate::rules::*;
#[derive(Debug, Eq, PartialEq)]
pub enum PluralCategory {
ZERO,
ONE,
TWO,
FEW,
MANY,
OTHER,
}
#[derive(Copy, Clone, Hash, PartialEq, Eq)]
pub enum PluralRuleType {
ORDINAL,
CARDINAL,
}
pub use crate::rules::CLDR_VERSION;
#[derive(Clone)]
pub struct PluralRules {
locale: LanguageIdentifier,
function: PluralRule,
}
impl PluralRules {
pub fn create<L: Into<LanguageIdentifier>>(
langid: L,
prt: PluralRuleType,
) -> Result<Self, &'static str> {
let langid = langid.into();
let returned_rule = match prt {
PluralRuleType::CARDINAL => {
let idx = rules::PRS_CARDINAL.binary_search_by_key(&&langid, |(l, _)| l);
idx.map(|idx| rules::PRS_CARDINAL[idx].1)
}
PluralRuleType::ORDINAL => {
let idx = rules::PRS_ORDINAL.binary_search_by_key(&&langid, |(l, _)| l);
idx.map(|idx| rules::PRS_ORDINAL[idx].1)
}
};
match returned_rule {
Ok(returned_rule) => Ok(Self {
locale: langid,
function: returned_rule,
}),
Err(_) => Err("unknown locale"),
}
}
pub fn select<N: TryInto<PluralOperands>>(
&self,
number: N,
) -> Result<PluralCategory, &'static str> {
let ops = number.try_into();
let pr = self.function;
match ops {
Ok(ops) => Ok(pr(&ops)),
Err(_) => Err("Argument can not be parsed to operands."),
}
}
pub fn get_locales(prt: PluralRuleType) -> Vec<LanguageIdentifier> {
let prs = match prt {
PluralRuleType::CARDINAL => rules::PRS_CARDINAL,
PluralRuleType::ORDINAL => rules::PRS_ORDINAL,
};
prs.iter().map(|(l, _)| l.clone()).collect()
}
pub fn get_locale(&self) -> &LanguageIdentifier {
&self.locale
}
}
#[cfg(test)]
mod tests {
use super::{PluralCategory, PluralRuleType, PluralRules, CLDR_VERSION};
use unic_langid::LanguageIdentifier;
#[test]
fn cardinals_test() {
let langid: LanguageIdentifier = "naq".parse().expect("Parsing failed.");
let pr_naq = PluralRules::create(langid, PluralRuleType::CARDINAL).unwrap();
assert_eq!(pr_naq.select(1), Ok(PluralCategory::ONE));
assert_eq!(pr_naq.select(2), Ok(PluralCategory::TWO));
assert_eq!(pr_naq.select(5), Ok(PluralCategory::OTHER));
let langid: LanguageIdentifier = "xx".parse().expect("Parsing failed.");
let pr_broken = PluralRules::create(langid, PluralRuleType::CARDINAL);
assert_eq!(pr_broken.is_err(), !pr_broken.is_ok());
}
#[test]
fn ordinals_rules() {
let langid: LanguageIdentifier = "uk".parse().expect("Parsing failed.");
let pr_naq = PluralRules::create(langid, PluralRuleType::ORDINAL).unwrap();
assert_eq!(pr_naq.select(33), Ok(PluralCategory::FEW));
assert_eq!(pr_naq.select(113), Ok(PluralCategory::OTHER));
}
#[test]
fn version_test() {
assert_eq!(CLDR_VERSION, 37);
}
#[test]
fn locale_test() {
assert_eq!(
PluralRules::get_locales(PluralRuleType::CARDINAL).is_empty(),
false
);
}
}