use {
rust_icu_common as common,
rust_icu_sys::{self as sys, versioned_function, *},
rust_icu_uenum as uenum, rust_icu_ustring as ustring,
rust_icu_ustring::buffered_uchar_method_with_retry,
std::{convert::TryFrom, convert::TryInto, ffi, ptr},
};
#[derive(Debug)]
pub struct UPluralRules {
rep: ptr::NonNull<sys::UPluralRules>,
}
impl Drop for UPluralRules {
fn drop(&mut self) {
unsafe { versioned_function!(uplrules_close)(self.rep.as_ptr()) };
}
}
impl UPluralRules {
pub fn try_new(locale: &str) -> Result<UPluralRules, common::Error> {
let locale_cstr = ffi::CString::new(locale)?;
let mut status = common::Error::OK_CODE;
let rep = unsafe {
assert!(common::Error::is_ok(status));
versioned_function!(uplrules_open)(locale_cstr.as_ptr(), &mut status)
as *mut sys::UPluralRules
};
common::Error::ok_or_warning(status)?;
assert_ne!(rep, 0 as *mut sys::UPluralRules);
Ok(UPluralRules {
rep: ptr::NonNull::new(rep).unwrap(),
})
}
pub fn try_new_styled(
locale: &str,
format_type: sys::UPluralType,
) -> Result<UPluralRules, common::Error> {
let locale_cstr = ffi::CString::new(locale)?;
let mut status = common::Error::OK_CODE;
let rep = unsafe {
assert!(common::Error::is_ok(status));
versioned_function!(uplrules_openForType)(
locale_cstr.as_ptr(),
format_type,
&mut status,
) as *mut sys::UPluralRules
};
common::Error::ok_or_warning(status)?;
Ok(UPluralRules {
rep: ptr::NonNull::new(rep).unwrap(),
})
}
pub fn select_ustring(&self, number: f64) -> Result<ustring::UChar, common::Error> {
const BUFFER_CAPACITY: usize = 20;
buffered_uchar_method_with_retry!(
select_impl,
BUFFER_CAPACITY,
[rep: *const sys::UPluralRules, number: f64,],
[]
);
select_impl(
versioned_function!(uplrules_select),
self.rep.as_ptr(),
number,
)
}
pub fn select(&self, number: f64) -> Result<String, common::Error> {
let result = self.select_ustring(number);
match result {
Err(e) => Err(e),
Ok(u) => String::try_from(&u).map_err(|e| e.into()),
}
}
pub fn get_keywords(&self) -> Result<uenum::Enumeration, common::Error> {
let mut status = UErrorCode::U_ZERO_ERROR;
let raw_enum = unsafe {
assert_eq!(status, UErrorCode::U_ZERO_ERROR);
versioned_function!(uplrules_getKeywords)(self.rep.as_ptr(), &mut status)
};
common::Error::ok_or_warning(status)?;
Ok(unsafe {
assert_ne!(raw_enum, 0 as *mut sys::UEnumeration);
uenum::Enumeration::from_raw_parts(None, raw_enum)
})
}
}
#[cfg(test)]
mod testing {
use super::*;
#[test]
fn plurals_ar_eg() -> Result<(), common::Error> {
let pl = crate::UPluralRules::try_new("ar_EG").expect("locale ar_EG exists");
assert_eq!("zero", pl.select(0 as f64)?);
assert_eq!("one", pl.select(1 as f64)?);
assert_eq!("two", pl.select(2 as f64)?);
assert_eq!("few", pl.select(6 as f64)?);
assert_eq!("many", pl.select(18 as f64)?);
Ok(())
}
#[test]
fn plurals_ar_eg_styled() -> Result<(), common::Error> {
let pl = crate::UPluralRules::try_new_styled("ar_EG", UPluralType::UPLURAL_TYPE_ORDINAL)
.expect("locale ar_EG exists");
assert_eq!("other", pl.select(0 as f64)?);
assert_eq!("other", pl.select(1 as f64)?);
assert_eq!("other", pl.select(2 as f64)?);
assert_eq!("other", pl.select(6 as f64)?);
assert_eq!("other", pl.select(18 as f64)?);
Ok(())
}
#[test]
fn plurals_sr_rs() -> Result<(), common::Error> {
let pl = crate::UPluralRules::try_new("sr_RS").expect("locale sr_RS exists");
assert_eq!("other", pl.select(0 as f64)?);
assert_eq!("one", pl.select(1 as f64)?);
assert_eq!("few", pl.select(2 as f64)?);
assert_eq!("few", pl.select(4 as f64)?);
assert_eq!("other", pl.select(5 as f64)?);
assert_eq!("other", pl.select(6 as f64)?);
assert_eq!("other", pl.select(18 as f64)?);
assert_eq!("other", pl.select(11 as f64)?);
assert_eq!("one", pl.select(21 as f64)?);
Ok(())
}
#[test]
fn plurals_sr_rs_styled() -> Result<(), common::Error> {
let pl = crate::UPluralRules::try_new_styled("sr_RS", UPluralType::UPLURAL_TYPE_ORDINAL)
.expect("locale sr_RS exists");
assert_eq!("other", pl.select(0 as f64)?);
assert_eq!("other", pl.select(1 as f64)?);
assert_eq!("other", pl.select(2 as f64)?);
assert_eq!("other", pl.select(6 as f64)?);
assert_eq!("other", pl.select(18 as f64)?);
Ok(())
}
#[test]
fn all_keywords() -> Result<(), common::Error> {
let pl = crate::UPluralRules::try_new("sr_RS").expect("locale sr_RS exists");
let e = pl.get_keywords()?;
let all: Vec<String> = e.into_iter().map(|r| r.unwrap()).collect();
assert_eq!(vec!["few", "one", "other"], all);
Ok(())
}
#[test]
fn all_keywords_styled() -> Result<(), common::Error> {
let pl = crate::UPluralRules::try_new_styled("sr_RS", UPluralType::UPLURAL_TYPE_ORDINAL)
.expect("locale sr_RS exists");
let e = pl.get_keywords()?;
let all: Vec<String> = e.into_iter().map(|r| r.unwrap()).collect();
assert_eq!(vec!["other"], all);
Ok(())
}
}