1use core::mem::MaybeUninit;
8use core::ops::Deref;
9use core::slice;
10
11use deranged::{ru8, ru16, ru32};
12
13static SINGLE_DIGITS: [u8; 10] = *b"0123456789";
14
15static ZERO_PADDED_PAIRS: [u8; 200] = *b"0001020304050607080910111213141516171819\
16 2021222324252627282930313233343536373839\
17 4041424344454647484950515253545556575859\
18 6061626364656667686970717273747576777879\
19 8081828384858687888990919293949596979899";
20
21#[cfg(feature = "formatting")]
22static SPACE_PADDED_PAIRS: [u8; 200] = *b" 0 1 2 3 4 5 6 7 8 910111213141516171819\
23 2021222324252627282930313233343536373839\
24 4041424344454647484950515253545556575859\
25 6061626364656667686970717273747576777879\
26 8081828384858687888990919293949596979899";
27
28#[derive(Clone, Copy)]
33pub(crate) struct StackStr<const MAX_LEN: usize> {
34 buf: [MaybeUninit<u8>; MAX_LEN],
35 len: usize,
36}
37
38impl<const MAX_LEN: usize> StackStr<MAX_LEN> {
39 #[inline]
44 pub(crate) const unsafe fn new(buf: [MaybeUninit<u8>; MAX_LEN], len: usize) -> Self {
45 debug_assert!(len <= MAX_LEN);
46 Self { buf, len }
47 }
48}
49
50impl<const MAX_LEN: usize> Deref for StackStr<MAX_LEN> {
51 type Target = str;
52
53 #[inline]
54 fn deref(&self) -> &Self::Target {
55 unsafe { str_from_raw_parts(self.buf.as_ptr().cast(), self.len) }
58 }
59}
60
61#[inline]
66pub(crate) const unsafe fn str_from_raw_parts<'a>(ptr: *const u8, len: usize) -> &'a str {
67 unsafe { str::from_utf8_unchecked(slice::from_raw_parts(ptr, len)) }
71}
72
73#[inline]
74const fn div_100(n: ru16<0, 9_999>) -> [ru8<0, 99>; 2] {
75 const EXP: u32 = 19; const SIG: u32 = (1 << EXP) / 100 + 1;
77
78 let n = n.get();
79
80 let high = (n as u32 * SIG) >> EXP; let low = n as u32 - high * 100;
82
83 unsafe {
86 [
87 ru8::new_unchecked(high as u8),
88 ru8::new_unchecked(low as u8),
89 ]
90 }
91}
92
93#[inline]
95pub(crate) const fn single_digit(n: ru8<0, 9>) -> &'static str {
96 unsafe { str_from_raw_parts(SINGLE_DIGITS.as_ptr().add(n.get() as usize), 1) }
99}
100
101#[inline]
104pub(crate) const fn one_to_two_digits_no_padding(n: ru8<0, 99>) -> &'static str {
105 let n = n.get();
106 let is_single_digit = n < 10;
107 unsafe {
110 str_from_raw_parts(
111 ZERO_PADDED_PAIRS
112 .as_ptr()
113 .add((n as usize) * 2 + is_single_digit as usize),
114 2 - is_single_digit as usize,
115 )
116 }
117}
118
119#[inline]
122pub(crate) const fn two_digits_zero_padded(n: ru8<0, 99>) -> &'static str {
123 unsafe { str_from_raw_parts(ZERO_PADDED_PAIRS.as_ptr().add((n.get() as usize) * 2), 2) }
126}
127
128#[inline]
131#[cfg(feature = "formatting")]
132pub(crate) const fn two_digits_space_padded(n: ru8<0, 99>) -> &'static str {
133 unsafe { str_from_raw_parts(SPACE_PADDED_PAIRS.as_ptr().add((n.get() as usize) * 2), 2) }
136}
137
138#[inline]
141#[cfg(feature = "formatting")]
142pub(crate) fn one_to_three_digits_no_padding(n: ru16<0, 999>) -> [&'static str; 2] {
143 if let Some(n) = n.narrow::<0, 99>() {
144 crate::hint::cold_path();
145 ["", one_to_two_digits_no_padding(n.into())]
146 } else {
147 three_digits_zero_padded(n)
148 }
149}
150
151#[inline]
154#[cfg(feature = "formatting")]
155pub(crate) const fn three_digits_zero_padded(n: ru16<0, 999>) -> [&'static str; 2] {
156 let [high, low] = div_100(n.expand());
157 [
158 single_digit(unsafe { high.narrow_unchecked() }),
160 two_digits_zero_padded(low),
161 ]
162}
163
164#[inline]
167#[cfg(feature = "formatting")]
168pub(crate) const fn three_digits_space_padded(n: ru16<0, 999>) -> [&'static str; 2] {
169 let [high, low] = div_100(n.expand());
170
171 if let Some(high) = high.narrow::<1, 9>() {
172 [single_digit(high.expand()), two_digits_zero_padded(low)]
173 } else {
174 [" ", two_digits_space_padded(low)]
175 }
176}
177
178#[inline]
181#[cfg(feature = "formatting")]
182pub(crate) fn one_to_four_digits_no_padding(n: ru16<0, 9_999>) -> [&'static str; 2] {
183 if let Some(n) = n.narrow::<0, 999>() {
184 crate::hint::cold_path();
185 one_to_three_digits_no_padding(n)
186 } else {
187 four_digits_zero_padded(n)
188 }
189}
190
191#[inline]
194pub(crate) const fn four_digits_zero_padded(n: ru16<0, 9_999>) -> [&'static str; 2] {
195 let [high, low] = div_100(n);
196 [two_digits_zero_padded(high), two_digits_zero_padded(low)]
197}
198
199#[inline]
202#[cfg(feature = "formatting")]
203pub(crate) const fn four_digits_space_padded(n: ru16<0, 9_999>) -> [&'static str; 2] {
204 let [high, low] = div_100(n);
205
206 if high.get() == 0 {
207 [" ", two_digits_space_padded(low)]
208 } else {
209 [two_digits_space_padded(high), two_digits_zero_padded(low)]
210 }
211}
212
213#[inline]
217pub(crate) const fn four_to_six_digits(n: ru32<0, 999_999>) -> [&'static str; 3] {
218 let n = n.get();
219
220 let (first_two, remaining) = (n / 10_000, n % 10_000);
221
222 let size = 2 - (first_two < 10) as usize - (first_two == 0) as usize;
223 let offset = first_two as usize * 2 + 2 - size;
224
225 let first_two = unsafe { str_from_raw_parts(ZERO_PADDED_PAIRS.as_ptr().add(offset), size) };
228 let [second_two, last_two] =
230 four_digits_zero_padded(unsafe { ru16::new_unchecked(remaining as u16) });
231 [first_two, second_two, last_two]
232}
233
234#[inline]
238#[cfg(feature = "formatting")]
239pub(crate) const fn five_digits_zero_padded(n: ru32<0, 99_999>) -> [&'static str; 3] {
240 let n = n.get();
241
242 let (first_one, remaining) = (n / 10_000, n % 10_000);
243
244 let first_one = single_digit(unsafe { ru8::new_unchecked(first_one as u8) });
246 let [second_two, last_two] =
248 four_digits_zero_padded(unsafe { ru16::new_unchecked(remaining as u16) });
249 [first_one, second_two, last_two]
250}
251
252#[inline]
255#[cfg(feature = "formatting")]
256pub(crate) const fn six_digits_zero_padded(n: ru32<0, 999_999>) -> [&'static str; 3] {
257 let n = n.get();
258
259 let (first_two, remaining) = (n / 10_000, n % 10_000);
260
261 let first_two = two_digits_zero_padded(unsafe { ru8::new_unchecked(first_two as u8) });
263 let [second_two, last_two] =
265 four_digits_zero_padded(unsafe { ru16::new_unchecked(remaining as u16) });
266 [first_two, second_two, last_two]
267}
268
269#[inline]
275pub(crate) const fn subsecond_from_nanos(n: ru32<0, 999_999_999>) -> [&'static str; 5] {
276 let n = n.get();
277 let (digits_1_thru_5, digits_6_thru_9) = (n / 10_000, n % 10_000);
278 let (digit_1, digits_2_thru_5) = (digits_1_thru_5 / 10_000, digits_1_thru_5 % 10_000);
279
280 unsafe {
283 let digit_1 = single_digit(ru8::new_unchecked(digit_1 as u8));
284 let [digits_2_and_3, digits_4_and_5] =
285 four_digits_zero_padded(ru16::new_unchecked(digits_2_thru_5 as u16));
286 let [digits_6_and_7, digits_8_and_9] =
287 four_digits_zero_padded(ru16::new_unchecked(digits_6_thru_9 as u16));
288
289 [
290 digit_1,
291 digits_2_and_3,
292 digits_4_and_5,
293 digits_6_and_7,
294 digits_8_and_9,
295 ]
296 }
297}
298
299#[inline]
304pub(crate) const fn truncated_subsecond_from_nanos(n: ru32<0, 999_999_999>) -> StackStr<9> {
305 #[repr(C, align(8))]
306 #[derive(Clone, Copy)]
307 struct Digits {
308 _padding: MaybeUninit<[u8; 7]>,
309 digit_1: u8,
310 digits_2_thru_9: [u8; 8],
311 }
312
313 let [
314 digit_1,
315 digits_2_and_3,
316 digits_4_and_5,
317 digits_6_and_7,
318 digits_8_and_9,
319 ] = subsecond_from_nanos(n);
320
321 let buf = Digits {
324 _padding: MaybeUninit::uninit(),
325 digit_1: digit_1.as_bytes()[0],
326 digits_2_thru_9: [
327 digits_2_and_3.as_bytes()[0],
328 digits_2_and_3.as_bytes()[1],
329 digits_4_and_5.as_bytes()[0],
330 digits_4_and_5.as_bytes()[1],
331 digits_6_and_7.as_bytes()[0],
332 digits_6_and_7.as_bytes()[1],
333 digits_8_and_9.as_bytes()[0],
334 digits_8_and_9.as_bytes()[1],
335 ],
336 };
337
338 let bitmask = u64::from_le_bytes(buf.digits_2_thru_9) ^ u64::from_le_bytes([b'0'; 8]);
342 let digits_to_truncate = bitmask.leading_zeros() / 8;
343 let len = 9 - digits_to_truncate as usize;
344
345 unsafe {
349 StackStr::new(
350 *(&raw const buf)
351 .byte_add(core::mem::offset_of!(Digits, digit_1))
352 .cast(),
353 len,
354 )
355 }
356}