use crate::IterableDataProviderCached;
use crate::SourceDataProvider;
use crate::cldr_serde;
use crate::cldr_serde::numbers::NumberPattern;
use crate::cldr_serde::numbers::NumberPatternItem;
use std::borrow::Cow;
use std::collections::HashSet;
use icu_pattern::DoublePlaceholderKey;
use icu_pattern::DoublePlaceholderPattern;
use icu_pattern::PatternItemCow;
use icu::experimental::dimension::provider::currency::no_currency::*;
use icu_provider::prelude::*;
impl DataProvider<CurrencyPatternsNoCurrencyV1> for SourceDataProvider {
fn load(
&self,
req: DataRequest,
) -> Result<DataResponse<CurrencyPatternsNoCurrencyV1>, DataError> {
self.check_req::<CurrencyPatternsNoCurrencyV1>(req)?;
let numbers_resource: &cldr_serde::numbers::Resource = self
.cldr()?
.numbers()
.read_and_parse(req.id.locale, "numbers.json")?;
let nsname = if !req.id.marker_attributes.is_empty() {
req.id.marker_attributes.as_str()
} else {
&numbers_resource.main.value.numbers.default_numbering_system
};
let result = extract_currency_no_currency(numbers_resource, nsname);
Ok(DataResponse {
metadata: Default::default(),
payload: DataPayload::from_owned(result?),
})
}
}
fn has_no_currency_pattern(patterns: &cldr_serde::numbers::CurrencyFormattingPatterns) -> bool {
patterns
.standard_no_currency
.as_ref()
.is_some_and(|p| !p.positive.is_empty())
|| !patterns.standard.positive.is_empty()
}
impl IterableDataProviderCached<CurrencyPatternsNoCurrencyV1> for SourceDataProvider {
fn iter_ids_cached(&self) -> Result<HashSet<DataIdentifierCow<'static>>, DataError> {
super::iter_numsys_pattern_ids(self, has_no_currency_pattern)
}
}
fn extract_currency_no_currency<'data>(
numbers_resource: &cldr_serde::numbers::Resource,
numsys_name: &str,
) -> Result<CurrencyPatternsNoCurrency<'data>, DataError> {
let numbers_block = &numbers_resource.main.value.numbers;
let currency_formats = numbers_block
.numsys_data
.currency_patterns
.get(numsys_name)
.ok_or_else(|| DataErrorKind::IdentifierNotFound.into_error())?;
if !has_no_currency_pattern(currency_formats) {
return Err(DataErrorKind::IdentifierNotFound.into_error());
}
let (minus_sign, plus_sign) =
if let Some(symbols) = numbers_block.numsys_data.symbols.get(numsys_name) {
(symbols.minus_sign.as_str(), symbols.plus_sign.as_str())
} else {
("-", "+")
};
fn convert_pattern_items<'a>(
items: &'a [NumberPatternItem],
minus_sign: &'a str,
plus_sign: &'a str,
) -> impl Iterator<Item = PatternItemCow<'a, DoublePlaceholderKey>> + 'a {
items.iter().flat_map(move |item| match item {
NumberPatternItem::DecimalSeparator => {
Some(PatternItemCow::Placeholder(DoublePlaceholderKey::Place0))
}
NumberPatternItem::Literal(s) => Some(PatternItemCow::Literal(Cow::Borrowed(s))),
NumberPatternItem::MinusSign => {
Some(PatternItemCow::Literal(Cow::Borrowed(minus_sign)))
}
NumberPatternItem::PlusSign => Some(PatternItemCow::Literal(Cow::Borrowed(plus_sign))),
_ => None,
})
}
let create_pattern =
|pattern: &NumberPattern| -> Result<Cow<'data, DoublePlaceholderPattern>, DataError> {
DoublePlaceholderPattern::try_from_items(convert_pattern_items(
&pattern.positive,
minus_sign,
plus_sign,
))
.map_err(|e| {
DataError::custom("Could not parse positive pattern").with_display_context(&e)
})
.map(Cow::Owned)
};
let create_negative_pattern = |pattern: &NumberPattern| -> Result<
Option<Cow<'data, DoublePlaceholderPattern>>,
DataError,
> {
if let Some(negative_items) = &pattern.negative {
DoublePlaceholderPattern::try_from_items(convert_pattern_items(
negative_items,
minus_sign,
plus_sign,
))
.map_err(|e| {
DataError::custom("Could not parse negative pattern").with_display_context(&e)
})
.map(Cow::Owned)
.map(Some)
} else {
Ok(None)
}
};
let standard_pattern = if let Some(std_nc) = ¤cy_formats.standard_no_currency {
std_nc
} else {
¤cy_formats.standard
};
let standard_pos = create_pattern(standard_pattern)?;
let standard_neg = create_negative_pattern(standard_pattern)?;
let (accounting_pos, accounting_neg) =
if let Some(acc_nc) = ¤cy_formats.accounting_no_currency {
(
Some(create_pattern(acc_nc)?),
create_negative_pattern(acc_nc)?,
)
} else if let Some(acc) = ¤cy_formats.accounting {
(Some(create_pattern(acc)?), create_negative_pattern(acc)?)
} else {
(None, None)
};
let mut patterns = super::PatternSet::new();
let standard_idx = patterns.add(Some(standard_pos)).unwrap();
let standard_neg_idx = patterns.add(standard_neg);
let accounting_pos_idx = patterns.add(accounting_pos).unwrap_or(standard_idx);
let accounting_neg_idx = patterns.add(accounting_neg);
let indices = NoCurrencyPatternIndices {
standard: standard_idx,
standard_negative: standard_neg_idx,
accounting_positive: accounting_pos_idx,
accounting_negative: accounting_neg_idx,
};
Ok(CurrencyPatternsNoCurrency {
patterns: patterns.into_var_zero_vec(),
indices,
})
}