1use crate::fixed::Fixed;
6
7#[derive(Clone, Copy, PartialEq, Eq, Debug)]
9pub enum Mode {
10 Dec,
12 Hex,
14 DecRational,
16}
17
18pub struct String {
21 buffer: [u8; 128],
22 length: usize,
23}
24
25#[derive(Clone, Copy, PartialEq, Eq, Debug)]
26enum ZeroMode {
27 NoLeadingZeros,
28 NoTrailingZeros,
29}
30
31impl String {
32 pub fn empty() -> Self {
34 Self { buffer: [0u8; 128], length: 0 }
35 }
36
37 pub fn new<I, const FRAC: usize>(
39 value: Fixed<I, FRAC>,
40 mode: Mode,
41 precision: Option<usize>,
42 ) -> Self
43 where
44 I: Into<i128> + Copy,
45 {
46 let mut s = Self::empty();
47 match mode {
48 Mode::Dec => s.write_dec(value, precision),
49 Mode::Hex => s.write_hex(value),
50 Mode::DecRational => s.write_dec_rational(value),
51 }
52 s
53 }
54
55 pub fn as_str(&self) -> &str {
57 self
58 }
59
60 fn push_byte(&mut self, b: u8) {
61 if self.length < self.buffer.len() {
62 self.buffer[self.length] = b;
63 self.length += 1;
64 }
65 }
66
67 fn write_dec_integer(&mut self, value: u128) {
68 let mut digits = [0u8; 39];
69 let mut len = 0;
70 let mut rem = value;
71 loop {
72 digits[len] = b'0' + (rem % 10) as u8;
73 len += 1;
74 rem /= 10;
75 if rem == 0 {
76 break;
77 }
78 }
79 for i in (0..len).rev() {
80 self.push_byte(digits[i]);
81 }
82 }
83
84 fn write_dec<I, const FRAC: usize>(&mut self, value: Fixed<I, FRAC>, precision: Option<usize>)
88 where
89 I: Into<i128> + Copy,
90 {
91 let raw = value.raw_value();
92 let raw_i: i128 = raw.into();
93 if raw_i < 0 {
94 self.push_byte(b'-');
95 }
96
97 let absolute_value = raw_i.unsigned_abs();
98 let integral_value = if FRAC >= 128 { 0 } else { absolute_value >> FRAC };
99
100 self.write_dec_integer(integral_value);
101
102 let max_digits = precision.unwrap_or(10);
103 if max_digits > 0 {
104 self.push_byte(b'.');
105 let start_pos = self.length;
106 let mut last_nonzero = start_pos;
107
108 let requested_stop = start_pos + max_digits;
109 let max_stop = self.buffer.len() - 1;
110 let stop = if requested_stop < max_stop { requested_stop } else { max_stop };
111
112 let mut remaining_value = absolute_value;
113 let frac_mask = (1u128 << FRAC) - 1;
114
115 let mut pos = start_pos;
116 loop {
117 remaining_value &= frac_mask;
118 remaining_value *= 10;
119 let digit_val = remaining_value >> FRAC;
120 let digit = b'0' + digit_val as u8;
121 if digit != b'0' {
122 last_nonzero = pos;
123 }
124 if pos < self.buffer.len() {
125 self.buffer[pos] = digit;
126 }
127 pos += 1;
128 remaining_value &= frac_mask;
129 if (remaining_value == 0 && precision.is_none()) || pos >= stop {
130 break;
131 }
132 }
133 if precision.is_some() {
134 self.length = stop;
135 } else {
136 self.length = last_nonzero + 1;
137 }
138 }
139 }
140
141 fn write_dec_rational<I, const FRAC: usize>(&mut self, value: Fixed<I, FRAC>)
142 where
143 I: Into<i128> + Copy,
144 {
145 assert!(FRAC <= 64, "Fixed-point types larger than 64 bits are not supported");
148 let raw = value.raw_value();
149 let raw_i: i128 = raw.into();
150 let sign = if raw_i < 0 { b'-' } else { b'+' };
151 if raw_i < 0 {
152 self.push_byte(b'-');
153 }
154
155 let absolute_value = raw_i.unsigned_abs();
158 let integral_value = if FRAC >= 128 { 0 } else { absolute_value >> FRAC };
159
160 self.write_dec_integer(integral_value);
161 self.push_byte(sign);
162
163 let frac_mask = if FRAC >= 128 { !0u128 } else { (1u128 << FRAC) - 1 };
164 self.write_dec_integer(absolute_value & frac_mask);
165 self.push_byte(b'/');
166
167 self.write_dec_integer(1u128 << FRAC);
168 }
169
170 fn write_hex<I, const FRAC: usize>(&mut self, value: Fixed<I, FRAC>)
171 where
172 I: Into<i128> + Copy,
173 {
174 let bits = core::mem::size_of::<I>() * 8;
175 let raw_value_mask = if bits == 64 { !0u64 } else { (1u64 << bits) - 1 };
176 let raw_i: i128 = value.raw_value().into();
177 let raw_value = (raw_i as u64) & raw_value_mask;
178
179 if FRAC == bits {
180 self.push_byte(b'0');
181 } else {
182 let integral_mask = if bits == 64 {
183 !0u64
184 } else {
185 (!((1u64.wrapping_shl(FRAC as u32)).wrapping_sub(1))) & raw_value_mask
186 };
187 let integral_value = (raw_value & integral_mask) >> FRAC;
188 let integral_hex_digits = (bits - FRAC).div_ceil(4);
189 let integral_shifted = integral_value << ((16 - integral_hex_digits) * 4);
190 self.write_hex_integer(integral_shifted, integral_hex_digits, ZeroMode::NoLeadingZeros);
191 }
192
193 self.push_byte(b'.');
194 if FRAC == 0 {
195 self.push_byte(b'0');
196 } else {
197 let frac_mask = if FRAC >= 64 { !0u64 } else { (1u64 << FRAC) - 1 };
198 let fractional_value = raw_value & frac_mask;
199 let fractional_shifted = fractional_value << (64 - FRAC);
200 let fractional_hex_digits = FRAC.div_ceil(4);
201 self.write_hex_integer(
202 fractional_shifted,
203 fractional_hex_digits,
204 ZeroMode::NoTrailingZeros,
205 );
206 }
207 }
208
209 fn write_hex_integer(&mut self, mut value: u64, digits: usize, zero_mode: ZeroMode) {
215 if value == 0 {
216 self.push_byte(b'0');
217 return;
218 }
219
220 let mut had_nonzero = false;
221 let mut last_nonzero = self.length;
222
223 for _ in 0..digits {
224 let digit = value >> 60;
225 if digit == 0 {
226 if zero_mode == ZeroMode::NoLeadingZeros && !had_nonzero {
227 value <<= 4;
228 continue;
229 }
230 } else {
231 had_nonzero = true;
232 last_nonzero = self.length;
233 }
234 if digit < 10 {
235 self.push_byte(b'0' + digit as u8);
236 } else {
237 self.push_byte(b'a' + (digit - 10) as u8);
238 }
239 value <<= 4;
240 }
241
242 if zero_mode == ZeroMode::NoTrailingZeros {
243 self.length = last_nonzero + 1;
244 }
245 }
246}
247
248impl core::ops::Deref for String {
249 type Target = str;
250
251 fn deref(&self) -> &Self::Target {
252 core::str::from_utf8(&self.buffer[..self.length]).unwrap()
253 }
254}
255
256impl core::fmt::Display for String {
257 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
258 f.write_str(self)
259 }
260}
261
262impl core::fmt::Debug for String {
263 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
264 f.write_str(self)
265 }
266}