use fixed_decimal::{FixedDecimal, Sign};
use icu_decimal::FixedDecimalFormatter;
use crate::alloc::borrow::ToOwned;
use alloc::borrow::Cow;
use writeable::Writeable;
use crate::dimension::provider::percent::PercentEssentialsV1;
use super::options::{Display, PercentFormatterOptions};
struct Append<W1, W2>(W1, W2);
impl<W1: Writeable, W2: Writeable> Writeable for Append<W1, W2> {
fn write_to<W>(&self, sink: &mut W) -> core::result::Result<(), core::fmt::Error>
where
W: core::fmt::Write + ?Sized,
{
self.0.write_to(sink)?;
self.1.write_to(sink)
}
}
pub struct FormattedPercent<'l> {
pub(crate) value: &'l FixedDecimal,
pub(crate) essential: &'l PercentEssentialsV1<'l>,
pub(crate) options: &'l PercentFormatterOptions,
pub(crate) fixed_decimal_formatter: &'l FixedDecimalFormatter,
}
impl Writeable for FormattedPercent<'_> {
fn write_to<W>(&self, sink: &mut W) -> core::result::Result<(), core::fmt::Error>
where
W: core::fmt::Write + ?Sized,
{
let abs_value = match self.value.sign() {
Sign::Negative => self.value.clone().with_sign(Sign::None),
_ => self.value.to_owned(),
};
let value = self.fixed_decimal_formatter.format(&abs_value);
match self.options.display {
Display::Standard => {
if self.value.sign() == Sign::Negative {
self.essential
.signed_pattern
.interpolate((value, &self.essential.minus_sign))
.write_to(sink)?
} else {
self.essential
.unsigned_pattern
.interpolate([value])
.write_to(sink)?
};
}
Display::Approximate => {
let sign = if self.value.sign() == Sign::Negative {
Append(
&self.essential.approximately_sign,
&self.essential.minus_sign,
)
} else {
Append(&self.essential.approximately_sign, &Cow::Borrowed(""))
};
self.essential
.signed_pattern
.interpolate((value, sign))
.write_to(sink)?;
}
Display::ExplicitSign => self
.essential
.signed_pattern
.interpolate((
value,
if self.value.sign() == Sign::Negative {
&self.essential.minus_sign
} else {
&self.essential.plus_sign
},
))
.write_to(sink)?,
};
Ok(())
}
}
writeable::impl_display_with_writeable!(FormattedPercent<'_>);
#[cfg(test)]
mod tests {
use icu_locale_core::locale;
use writeable::assert_writeable_eq;
use crate::dimension::percent::{
formatter::PercentFormatter,
options::{Display, PercentFormatterOptions},
};
#[test]
pub fn test_en_us() {
let locale = locale!("en-US").into();
let positive_value = "12345.67".parse().unwrap();
let default_fmt = PercentFormatter::try_new(&locale, Default::default()).unwrap();
let formatted_percent = default_fmt.format(&positive_value);
assert_writeable_eq!(formatted_percent, "12,345.67%");
let neg_value = "-12345.67".parse().unwrap();
let formatted_percent = default_fmt.format(&neg_value);
assert_writeable_eq!(formatted_percent, "-12,345.67%");
let approx_value = "12345.67".parse().unwrap();
let approx_fmt = PercentFormatter::try_new(
&locale,
PercentFormatterOptions {
display: Display::Approximate,
},
)
.unwrap();
let formatted_percent = approx_fmt.format(&approx_value);
assert_writeable_eq!(formatted_percent, "~12,345.67%");
let explicit_fmt = PercentFormatter::try_new(
&locale,
PercentFormatterOptions {
display: Display::ExplicitSign,
},
)
.unwrap();
let formatted_percent = explicit_fmt.format(&positive_value);
assert_writeable_eq!(formatted_percent, "+12,345.67%");
}
#[test]
pub fn test_tr() {
let locale = locale!("tr").into();
let positive_value = "12345.67".parse().unwrap();
let default_fmt = PercentFormatter::try_new(&locale, Default::default()).unwrap();
let formatted_percent = default_fmt.format(&positive_value);
assert_writeable_eq!(formatted_percent, "%12.345,67");
let neg_value = "-12345.67".parse().unwrap();
let formatted_percent = default_fmt.format(&neg_value);
assert_writeable_eq!(formatted_percent, "-%12.345,67");
let approx_value = "12345.67".parse().unwrap();
let approx_fmt = PercentFormatter::try_new(
&locale,
PercentFormatterOptions {
display: Display::Approximate,
},
)
.unwrap();
let formatted_percent = approx_fmt.format(&approx_value);
assert_writeable_eq!(formatted_percent, "~%12.345,67");
let explicit_fmt = PercentFormatter::try_new(
&locale,
PercentFormatterOptions {
display: Display::ExplicitSign,
},
)
.unwrap();
let formatted_percent = explicit_fmt.format(&positive_value);
assert_writeable_eq!(formatted_percent, "+%12.345,67");
}
#[test]
pub fn test_blo() {
let locale = locale!("blo").into();
let positive_value = "12345.67".parse().unwrap();
let default_fmt = PercentFormatter::try_new(&locale, Default::default()).unwrap();
let formatted_percent = default_fmt.format(&positive_value);
assert_writeable_eq!(formatted_percent, "%\u{a0}12\u{a0}345,67");
let neg_value = "-12345.67".parse().unwrap();
let formatted_percent = default_fmt.format(&neg_value);
assert_writeable_eq!(formatted_percent, "%\u{a0}-12\u{a0}345,67");
let approx_value = "12345.67".parse().unwrap();
let approx_fmt = PercentFormatter::try_new(
&locale,
PercentFormatterOptions {
display: Display::Approximate,
},
)
.unwrap();
let formatted_percent = approx_fmt.format(&approx_value);
assert_writeable_eq!(formatted_percent, "%\u{a0}~12\u{a0}345,67");
let explicit_fmt = PercentFormatter::try_new(
&locale,
PercentFormatterOptions {
display: Display::ExplicitSign,
},
)
.unwrap();
let formatted_percent = explicit_fmt.format(&positive_value);
assert_writeable_eq!(formatted_percent, "%\u{a0}+12\u{a0}345,67");
}
}