use core::fmt;
use core::fmt::Write;
use crate::common::fmt::write_u128;
use crate::locale::Locale;
use super::PercentOptions;
const POW10: [u64; 7] = [1, 10, 100, 1_000, 10_000, 100_000, 1_000_000];
pub fn format_percent<L: Locale>(
f: &mut fmt::Formatter<'_>,
value: f64,
options: &PercentOptions<L>,
) -> fmt::Result {
if !value.is_finite() {
return write!(f, "{value}%");
}
let percent = value * 100.0;
let negative = percent.is_sign_negative();
let abs = percent.abs();
let precision = options.precision;
let decimal_sep = options.locale.decimal_separator();
let factor = POW10[precision as usize] as f64;
let rounded = if abs * factor + 0.5 < u64::MAX as f64 {
let shifted = (abs * factor + 0.5) as u64;
shifted as f64 / factor
} else {
abs
};
let is_zero = rounded == 0.0;
if negative && !is_zero {
f.write_char('-')?;
} else if options.force_sign && !negative && !is_zero {
f.write_char('+')?;
}
let int_part = rounded as u128;
let frac_f = rounded - int_part as f64;
write_u128(f, int_part, false, options.locale.group_separator())?;
if precision > 0 {
let p = precision as usize;
let frac_shifted = (frac_f * factor + 0.5) as u64;
let frac_clamped = frac_shifted.min(factor as u64 - 1);
let mut buf = [b'0'; 6];
let mut rem = frac_clamped;
for i in (0..p).rev() {
buf[i] = b'0' + (rem % 10) as u8;
rem /= 10;
}
if options.fixed_precision {
f.write_char(decimal_sep)?;
let s = unsafe { core::str::from_utf8_unchecked(&buf[..p]) };
f.write_str(s)?;
} else {
let mut end = p;
while end > 0 && buf[end - 1] == b'0' {
end -= 1;
}
if end > 0 {
f.write_char(decimal_sep)?;
let s = unsafe { core::str::from_utf8_unchecked(&buf[..end]) };
f.write_str(s)?;
}
}
}
f.write_char('%')
}