use crate::cldr_serde;
use crate::IterableDataProviderCached;
use crate::SourceDataProvider;
use icu::experimental::dimension::provider::currency::fractions::*;
use icu_provider::prelude::*;
use std::collections::HashSet;
use zerovec::ZeroMap;
impl DataProvider<CurrencyFractionsV1> for SourceDataProvider {
fn load(&self, req: DataRequest) -> Result<DataResponse<CurrencyFractionsV1>, DataError> {
self.check_req::<CurrencyFractionsV1>(req)?;
let resource: &cldr_serde::currencies::supplemental::Resource = self
.cldr()?
.core()
.read_and_parse("supplemental/currencyData.json")?;
let cldr_fractions = &resource.supplemental.currency_data.fractions;
let default = parse_rounding_modes(&cldr_fractions.default)?;
let mut fractions_map = std::collections::BTreeMap::new();
for (iso_code, modes) in &cldr_fractions.currencies {
let info = parse_rounding_modes(modes)?;
if info != default {
fractions_map.insert(iso_code.to_unvalidated(), info);
}
}
Ok(DataResponse {
metadata: Default::default(),
payload: DataPayload::from_owned(CurrencyFractions {
fractions: ZeroMap::from_iter(fractions_map.iter()),
default,
}),
})
}
}
impl IterableDataProviderCached<CurrencyFractionsV1> for SourceDataProvider {
fn iter_ids_cached(&self) -> Result<HashSet<DataIdentifierCow<'static>>, DataError> {
Ok(HashSet::from_iter([Default::default()]))
}
}
fn parse_rounding_modes(
modes: &cldr_serde::currencies::supplemental::RoundingModes,
) -> Result<FractionInfo, DataError> {
let digits = modes
.digits
.as_ref()
.map(|s| s.parse::<u8>())
.transpose()
.map_err(|_| DataError::custom("Invalid digits value"))?
.unwrap_or(2);
let rounding = modes
.rounding
.as_ref()
.map(|s| s.parse::<u8>())
.transpose()
.map_err(|_| DataError::custom("Invalid rounding value"))?
.unwrap_or(0);
let cash_digits = modes
.cash_digits
.as_ref()
.map(|s| s.parse::<u8>())
.transpose()
.map_err(|_| DataError::custom("Invalid cash_digits value"))?;
let cash_rounding = modes
.cash_rounding
.as_ref()
.map(|s| s.parse::<u8>())
.transpose()
.map_err(|_| DataError::custom("Invalid cash_rounding value"))?;
Ok(FractionInfo {
digits,
rounding,
cash_digits,
cash_rounding,
})
}
#[test]
fn test_basic() {
let provider = SourceDataProvider::new_testing();
let response: DataResponse<CurrencyFractionsV1> = provider.load(Default::default()).unwrap();
let data = response.payload.get();
assert_eq!(data.default.digits, 2);
assert_eq!(data.default.rounding, 0);
assert_eq!(data.default.cash_digits, None);
assert_eq!(data.default.cash_rounding, None);
let jpy = tinystr::tinystr!(3, "JPY").to_unvalidated();
if let Some(jpy_info) = data.fractions.get(&jpy) {
let info: FractionInfo = zerovec::ule::AsULE::from_unaligned(*jpy_info);
assert_eq!(info.digits, 0);
}
let chf = tinystr::tinystr!(3, "CHF").to_unvalidated();
if let Some(chf_info) = data.fractions.get(&chf) {
let info: FractionInfo = zerovec::ule::AsULE::from_unaligned(*chf_info);
assert_eq!(info.cash_rounding, Some(5));
}
}