use {
rust_icu_common as common, rust_icu_sys as sys,
rust_icu_sys::*,
std::{convert::TryFrom, ffi, str},
};
#[derive(Debug)]
pub struct Enumeration {
_raw: Option<common::CStringVec>,
rep: *mut sys::UEnumeration,
}
impl Enumeration {
pub fn repr(&mut self) -> *mut sys::UEnumeration {
self.rep
}
pub fn empty() -> Self {
Enumeration::try_from(&vec![][..]).unwrap()
}
}
impl Default for Enumeration {
fn default() -> Self {
Self::empty()
}
}
impl TryFrom<&[&str]> for Enumeration {
type Error = common::Error;
fn try_from(v: &[&str]) -> Result<Enumeration, common::Error> {
let raw = common::CStringVec::new(v)?;
let mut status = common::Error::OK_CODE;
let rep: *mut sys::UEnumeration = unsafe {
versioned_function!(uenum_openCharStringsEnumeration)(
raw.as_c_array(),
raw.len() as i32,
&mut status,
)
};
common::Error::ok_or_warning(status)?;
assert!(!rep.is_null());
Ok(Enumeration {
rep,
_raw: Some(raw),
})
}
}
impl Drop for Enumeration {
fn drop(&mut self) {
unsafe { versioned_function!(uenum_close)(self.rep) };
}
}
impl Iterator for Enumeration {
type Item = Result<String, common::Error>;
fn next(&mut self) -> Option<Self::Item> {
let mut len: i32 = 0;
let mut status = common::Error::OK_CODE;
assert!(!self.rep.is_null());
let raw = unsafe { versioned_function!(uenum_next)(self.rep, &mut len, &mut status) };
if raw.is_null() {
return None;
}
let result = common::Error::ok_or_warning(status);
match result {
Ok(()) => {
assert!(!raw.is_null());
let cstring = unsafe { ffi::CStr::from_ptr(raw) }; Some(Ok(cstring
.to_str()
.expect("could not convert to string")
.to_string()))
}
Err(e) => Some(Err(e)),
}
}
}
impl Enumeration {
#[doc(hidden)]
pub unsafe fn from_raw_parts(
_raw: Option<common::CStringVec>,
rep: *mut sys::UEnumeration,
) -> Enumeration {
Enumeration { _raw, rep }
}
}
#[doc(hidden)]
pub fn ucal_open_country_time_zones(country: &str) -> Result<Enumeration, common::Error> {
let mut status = common::Error::OK_CODE;
let asciiz_country = ffi::CString::new(country)?;
let raw_enum = unsafe {
assert!(common::Error::is_ok(status));
versioned_function!(ucal_openCountryTimeZones)(asciiz_country.as_ptr(), &mut status)
};
common::Error::ok_or_warning(status)?;
Ok(Enumeration {
_raw: None,
rep: raw_enum,
})
}
#[doc(hidden)]
pub fn ucal_open_time_zone_id_enumeration(
zone_type: sys::USystemTimeZoneType,
region: Option<&str>,
raw_offset: Option<i32>,
) -> Result<Enumeration, common::Error> {
let mut status = common::Error::OK_CODE;
let asciiz_region = match region {
None => None,
Some(region) => Some(ffi::CString::new(region)?),
};
let mut repr_raw_offset: i32 = raw_offset.unwrap_or_default();
let raw_enum = unsafe {
assert!(common::Error::is_ok(status));
versioned_function!(ucal_openTimeZoneIDEnumeration)(
zone_type,
match &asciiz_region {
Some(asciiz_region) => asciiz_region.as_ptr(),
None => std::ptr::null(),
},
match raw_offset {
Some(_) => &mut repr_raw_offset,
None => std::ptr::null_mut(),
},
&mut status,
)
};
common::Error::ok_or_warning(status)?;
Ok(Enumeration {
_raw: None,
rep: raw_enum,
})
}
#[doc(hidden)]
pub fn open_time_zones() -> Result<Enumeration, common::Error> {
let mut status = common::Error::OK_CODE;
let raw_enum = unsafe {
assert!(common::Error::is_ok(status));
versioned_function!(ucal_openTimeZones)(&mut status)
};
common::Error::ok_or_warning(status)?;
Ok(Enumeration {
_raw: None,
rep: raw_enum,
})
}
#[doc(hidden)]
#[deprecated(since="4.2.4", note="please use `ULoc::open_keywords` instead")]
pub fn uloc_open_keywords(locale: &str) -> Result<Enumeration, common::Error> {
let mut status = common::Error::OK_CODE;
let asciiz_locale = ffi::CString::new(locale)?;
let raw_enum = unsafe {
assert!(common::Error::is_ok(status));
versioned_function!(uloc_openKeywords)(asciiz_locale.as_ptr(), &mut status)
};
common::Error::ok_or_warning(status)?;
if raw_enum.is_null() {
Ok(Enumeration::empty())
} else {
Ok(Enumeration {
_raw: None,
rep: raw_enum,
})
}
}
#[cfg(test)]
mod tests {
use {super::*, std::convert::TryFrom};
#[test]
fn iter() {
let e = Enumeration::try_from(&vec!["hello", "world", "💖"][..]).expect("enumeration?");
let mut count = 0;
let mut results = vec![];
for result in e {
let elem = result.expect("no error");
count += 1;
results.push(elem);
}
assert_eq!(count, 3, "results: {:?}", results);
assert_eq!(
results,
vec!["hello", "world", "💖"],
"results: {:?}",
results
);
}
#[test]
fn error() {
let destroyed_sparkle_heart = vec![0, 159, 164, 150];
let invalid_utf8 = unsafe { str::from_utf8_unchecked(&destroyed_sparkle_heart) };
let e = Enumeration::try_from(&vec!["hello", "world", "💖", invalid_utf8][..]);
assert!(e.is_err(), "was: {:?}", e);
}
#[test]
fn test_uloc_open_keywords() -> Result<(), common::Error> {
let loc = "az-Cyrl-AZ-u-ca-hebrew-fw-sunday-nu-deva-tz-usnyc";
#[allow(deprecated)]
let keywords: Vec<String> = uloc_open_keywords(loc).unwrap().map(|result| result.unwrap()).collect();
assert_eq!(
keywords,
vec![
"calendar".to_string(),
"fw".to_string(),
"numbers".to_string(),
"timezone".to_string()
]
);
Ok(())
}
}