use core::fmt;
use core::str::FromStr;
use crate::Decimal;
use crate::error::ParseError;
const DIGIT_PAIRS: &[u8; 200] = b"\
00010203040506070809\
10111213141516171819\
20212223242526272829\
30313233343536373839\
40414243444546474849\
50515253545556575859\
60616263646566676869\
70717273747576777879\
80818283848586878889\
90919293949596979899";
macro_rules! impl_decimal_format {
($backing:ty, $unsigned:ty) => {
impl<const D: u8> Decimal<$backing, D> {
pub fn write_to_buf(&self, buf: &mut [u8]) -> usize {
debug_assert!(buf.len() >= 64);
if self.value == 0 {
buf[0] = b'0';
return 1;
}
let negative = self.value < 0;
let abs = if negative {
self.value.unsigned_abs()
} else {
self.value as $unsigned
};
let scale = Self::SCALE as $unsigned;
let integer = abs / scale;
let frac = abs % scale;
let mut pos = 0;
if negative {
buf[pos] = b'-';
pos += 1;
}
let mut int_buf = [0u8; 40];
let mut int_pos = 40;
let mut val = integer;
while val >= 100 {
int_pos -= 2;
let d = (val % 100) as usize * 2;
int_buf[int_pos] = DIGIT_PAIRS[d];
int_buf[int_pos + 1] = DIGIT_PAIRS[d + 1];
val /= 100;
}
if val >= 10 {
int_pos -= 2;
let d = val as usize * 2;
int_buf[int_pos] = DIGIT_PAIRS[d];
int_buf[int_pos + 1] = DIGIT_PAIRS[d + 1];
} else {
int_pos -= 1;
int_buf[int_pos] = b'0' + val as u8;
}
let int_len = 40 - int_pos;
buf[pos..pos + int_len].copy_from_slice(&int_buf[int_pos..40]);
pos += int_len;
if frac > 0 {
buf[pos] = b'.';
pos += 1;
let mut frac_buf = [b'0'; 40];
let mut frac_val = frac;
let mut frac_pos = D as usize;
while frac_val >= 100 && frac_pos >= 2 {
frac_pos -= 2;
let d = (frac_val % 100) as usize * 2;
frac_buf[frac_pos] = DIGIT_PAIRS[d];
frac_buf[frac_pos + 1] = DIGIT_PAIRS[d + 1];
frac_val /= 100;
}
while frac_val > 0 && frac_pos > 0 {
frac_pos -= 1;
frac_buf[frac_pos] = b'0' + (frac_val % 10) as u8;
frac_val /= 10;
}
let mut end = D as usize;
while end > 0 && frac_buf[end - 1] == b'0' {
end -= 1;
}
buf[pos..pos + end].copy_from_slice(&frac_buf[..end]);
pos += end;
}
pos
}
}
impl<const D: u8> fmt::Display for Decimal<$backing, D> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let mut buf = [0u8; 64];
let len = self.write_to_buf(&mut buf);
let s = unsafe { core::str::from_utf8_unchecked(&buf[..len]) };
f.write_str(s)
}
}
impl<const D: u8> fmt::Debug for Decimal<$backing, D> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
if f.alternate() {
f.debug_struct("Decimal")
.field("value", &self.value)
.finish()
} else {
write!(f, "{self}")
}
}
}
impl<const D: u8> FromStr for Decimal<$backing, D> {
type Err = ParseError;
#[inline]
fn from_str(s: &str) -> Result<Self, ParseError> {
Self::from_str_exact(s)
}
}
};
}
impl_decimal_format!(i32, u32);
impl_decimal_format!(i64, u64);
impl_decimal_format!(i128, u128);