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