1use core::fmt;
4use core::str::FromStr;
5
6use crate::Decimal;
7use crate::error::ParseError;
8
9const DIGIT_PAIRS: &[u8; 200] = b"\
11 00010203040506070809\
12 10111213141516171819\
13 20212223242526272829\
14 30313233343536373839\
15 40414243444546474849\
16 50515253545556575859\
17 60616263646566676869\
18 70717273747576777879\
19 80818283848586878889\
20 90919293949596979899";
21
22macro_rules! impl_decimal_format {
23 ($backing:ty, $unsigned:ty) => {
24 impl<const D: u8> Decimal<$backing, D> {
25 pub fn write_to_buf(&self, buf: &mut [u8]) -> usize {
31 debug_assert!(buf.len() >= 64);
32
33 if self.value == 0 {
34 buf[0] = b'0';
35 return 1;
36 }
37
38 let negative = self.value < 0;
39 let abs = if negative {
40 self.value.unsigned_abs()
41 } else {
42 self.value as $unsigned
43 };
44
45 let scale = Self::SCALE as $unsigned;
46 let integer = abs / scale;
47 let frac = abs % scale;
48
49 let mut pos = 0;
50
51 if negative {
53 buf[pos] = b'-';
54 pos += 1;
55 }
56
57 let mut int_buf = [0u8; 40];
59 let mut int_pos = 40;
60 let mut val = integer;
61 while val >= 100 {
62 int_pos -= 2;
63 let d = (val % 100) as usize * 2;
64 int_buf[int_pos] = DIGIT_PAIRS[d];
65 int_buf[int_pos + 1] = DIGIT_PAIRS[d + 1];
66 val /= 100;
67 }
68 if val >= 10 {
69 int_pos -= 2;
70 let d = val as usize * 2;
71 int_buf[int_pos] = DIGIT_PAIRS[d];
72 int_buf[int_pos + 1] = DIGIT_PAIRS[d + 1];
73 } else {
74 int_pos -= 1;
75 int_buf[int_pos] = b'0' + val as u8;
76 }
77 let int_len = 40 - int_pos;
78 buf[pos..pos + int_len].copy_from_slice(&int_buf[int_pos..40]);
79 pos += int_len;
80
81 if frac > 0 {
83 buf[pos] = b'.';
84 pos += 1;
85
86 let mut frac_buf = [b'0'; 40];
87 let mut frac_val = frac;
88 let mut frac_pos = D as usize;
89
90 while frac_val >= 100 && frac_pos >= 2 {
91 frac_pos -= 2;
92 let d = (frac_val % 100) as usize * 2;
93 frac_buf[frac_pos] = DIGIT_PAIRS[d];
94 frac_buf[frac_pos + 1] = DIGIT_PAIRS[d + 1];
95 frac_val /= 100;
96 }
97 while frac_val > 0 && frac_pos > 0 {
98 frac_pos -= 1;
99 frac_buf[frac_pos] = b'0' + (frac_val % 10) as u8;
100 frac_val /= 10;
101 }
102
103 let mut end = D as usize;
105 while end > 0 && frac_buf[end - 1] == b'0' {
106 end -= 1;
107 }
108
109 buf[pos..pos + end].copy_from_slice(&frac_buf[..end]);
110 pos += end;
111 }
112
113 pos
114 }
115 }
116
117 impl<const D: u8> fmt::Display for Decimal<$backing, D> {
118 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
119 let mut buf = [0u8; 64];
120 let len = self.write_to_buf(&mut buf);
121 let s = unsafe { core::str::from_utf8_unchecked(&buf[..len]) };
123 f.write_str(s)
124 }
125 }
126
127 impl<const D: u8> fmt::Debug for Decimal<$backing, D> {
128 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
129 if f.alternate() {
130 f.debug_struct("Decimal")
131 .field("value", &self.value)
132 .finish()
133 } else {
134 write!(f, "{self}")
135 }
136 }
137 }
138
139 impl<const D: u8> FromStr for Decimal<$backing, D> {
140 type Err = ParseError;
141
142 #[inline]
143 fn from_str(s: &str) -> Result<Self, ParseError> {
144 Self::from_str_exact(s)
145 }
146 }
147 };
148}
149
150impl_decimal_format!(i32, u32);
151impl_decimal_format!(i64, u64);
152impl_decimal_format!(i128, u128);