1use core::mem::MaybeUninit;
8use core::ops::Deref;
9use core::{ptr, slice};
10
11#[cfg(feature = "formatting")]
12use deranged::ru64;
13use deranged::{ru8, ru16, ru32};
14
15static SINGLE_DIGITS: [u8; 10] = *b"0123456789";
16
17static ZERO_PADDED_PAIRS: [u8; 200] = *b"0001020304050607080910111213141516171819\
18 2021222324252627282930313233343536373839\
19 4041424344454647484950515253545556575859\
20 6061626364656667686970717273747576777879\
21 8081828384858687888990919293949596979899";
22
23#[cfg(feature = "formatting")]
24static SPACE_PADDED_PAIRS: [u8; 200] = *b" 0 1 2 3 4 5 6 7 8 910111213141516171819\
25 2021222324252627282930313233343536373839\
26 4041424344454647484950515253545556575859\
27 6061626364656667686970717273747576777879\
28 8081828384858687888990919293949596979899";
29
30#[derive(Clone, Copy)]
35pub(crate) struct StackStr<const MAX_LEN: usize> {
36 buf: [MaybeUninit<u8>; MAX_LEN],
37 len: usize,
38}
39
40impl<const MAX_LEN: usize> StackStr<MAX_LEN> {
41 #[inline]
46 pub(crate) const unsafe fn new(buf: [MaybeUninit<u8>; MAX_LEN], len: usize) -> Self {
47 debug_assert!(len <= MAX_LEN);
48 Self { buf, len }
49 }
50}
51
52impl<const MAX_LEN: usize> Deref for StackStr<MAX_LEN> {
53 type Target = str;
54
55 #[inline]
56 fn deref(&self) -> &Self::Target {
57 unsafe { str_from_raw_parts(self.buf.as_ptr().cast(), self.len) }
60 }
61}
62
63#[derive(Clone, Copy)]
68pub(crate) struct StackTrailingStr<const MAX_LEN: usize> {
69 buf: [MaybeUninit<u8>; MAX_LEN],
70 start_index: usize,
71}
72
73impl<const MAX_LEN: usize> StackTrailingStr<MAX_LEN> {
74 #[inline]
78 pub(crate) const unsafe fn new(buf: [MaybeUninit<u8>; MAX_LEN], start_index: usize) -> Self {
79 debug_assert!(start_index <= MAX_LEN);
80 Self { buf, start_index }
81 }
82
83 #[inline]
85 pub(crate) const fn len(&self) -> usize {
86 let len = MAX_LEN - self.start_index;
87 unsafe { core::hint::assert_unchecked(len <= MAX_LEN) };
90 len
91 }
92}
93
94impl<const MAX_LEN: usize> Deref for StackTrailingStr<MAX_LEN> {
95 type Target = str;
96
97 #[inline]
98 fn deref(&self) -> &Self::Target {
99 unsafe {
102 str_from_raw_parts(
103 self.buf.as_ptr().add(self.start_index).cast(),
104 MAX_LEN - self.start_index,
105 )
106 }
107 }
108}
109
110#[inline]
116const unsafe fn write_two_digits(buf: &mut [MaybeUninit<u8>], offset: usize, value: ru8<0, 99>) {
117 unsafe {
119 ptr::copy_nonoverlapping(
120 two_digits_zero_padded(value).as_ptr().cast(),
121 buf.as_mut_ptr().add(offset),
122 2,
123 );
124 }
125}
126
127#[inline]
133const unsafe fn write_one_digit(buf: &mut [MaybeUninit<u8>], offset: usize, value: ru8<0, 9>) {
134 unsafe {
136 ptr::copy_nonoverlapping(
137 single_digit(value).as_ptr().cast(),
138 buf.as_mut_ptr().add(offset),
139 1,
140 );
141 }
142}
143
144#[inline]
149pub(crate) const unsafe fn str_from_raw_parts<'a>(ptr: *const u8, len: usize) -> &'a str {
150 unsafe { str::from_utf8_unchecked(slice::from_raw_parts(ptr, len)) }
154}
155
156#[inline]
157const fn div_100(n: ru16<0, 9_999>) -> [ru8<0, 99>; 2] {
158 const EXP: u32 = 19; const SIG: u32 = (1 << EXP) / 100 + 1;
160
161 let n = n.get();
162
163 let high = (n as u32 * SIG) >> EXP; let low = n as u32 - high * 100;
165
166 unsafe {
169 [
170 ru8::new_unchecked(high as u8),
171 ru8::new_unchecked(low as u8),
172 ]
173 }
174}
175
176#[inline]
178pub(crate) const fn single_digit(n: ru8<0, 9>) -> &'static str {
179 unsafe { str_from_raw_parts(SINGLE_DIGITS.as_ptr().add(n.get() as usize), 1) }
182}
183
184#[inline]
187pub(crate) const fn one_to_two_digits_no_padding(n: ru8<0, 99>) -> &'static str {
188 let n = n.get();
189 let is_single_digit = n < 10;
190 unsafe {
193 str_from_raw_parts(
194 ZERO_PADDED_PAIRS
195 .as_ptr()
196 .add((n as usize) * 2 + is_single_digit as usize),
197 2 - is_single_digit as usize,
198 )
199 }
200}
201
202#[inline]
205pub(crate) const fn two_digits_zero_padded(n: ru8<0, 99>) -> &'static str {
206 unsafe { str_from_raw_parts(ZERO_PADDED_PAIRS.as_ptr().add((n.get() as usize) * 2), 2) }
209}
210
211#[inline]
214#[cfg(feature = "formatting")]
215pub(crate) const fn two_digits_space_padded(n: ru8<0, 99>) -> &'static str {
216 unsafe { str_from_raw_parts(SPACE_PADDED_PAIRS.as_ptr().add((n.get() as usize) * 2), 2) }
219}
220
221#[inline]
224#[cfg(feature = "formatting")]
225pub(crate) fn one_to_three_digits_no_padding(n: ru16<0, 999>) -> [&'static str; 2] {
226 if let Some(n) = n.narrow::<0, 99>() {
227 crate::hint::cold_path();
228 ["", one_to_two_digits_no_padding(n.into())]
229 } else {
230 three_digits_zero_padded(n)
231 }
232}
233
234#[inline]
237#[cfg(feature = "formatting")]
238pub(crate) const fn three_digits_zero_padded(n: ru16<0, 999>) -> [&'static str; 2] {
239 let [high, low] = div_100(n.expand());
240 [
241 single_digit(unsafe { high.narrow_unchecked() }),
243 two_digits_zero_padded(low),
244 ]
245}
246
247#[inline]
250#[cfg(feature = "formatting")]
251pub(crate) const fn three_digits_space_padded(n: ru16<0, 999>) -> [&'static str; 2] {
252 let [high, low] = div_100(n.expand());
253
254 if let Some(high) = high.narrow::<1, 9>() {
255 [single_digit(high.expand()), two_digits_zero_padded(low)]
256 } else {
257 [" ", two_digits_space_padded(low)]
258 }
259}
260
261#[inline]
264#[cfg(feature = "formatting")]
265pub(crate) fn one_to_four_digits_no_padding(n: ru16<0, 9_999>) -> [&'static str; 2] {
266 if let Some(n) = n.narrow::<0, 999>() {
267 crate::hint::cold_path();
268 one_to_three_digits_no_padding(n)
269 } else {
270 four_digits_zero_padded(n)
271 }
272}
273
274#[inline]
277pub(crate) const fn four_digits_zero_padded(n: ru16<0, 9_999>) -> [&'static str; 2] {
278 let [high, low] = div_100(n);
279 [two_digits_zero_padded(high), two_digits_zero_padded(low)]
280}
281
282#[inline]
285#[cfg(feature = "formatting")]
286pub(crate) const fn four_digits_space_padded(n: ru16<0, 9_999>) -> [&'static str; 2] {
287 let [high, low] = div_100(n);
288
289 if high.get() == 0 {
290 [" ", two_digits_space_padded(low)]
291 } else {
292 [two_digits_space_padded(high), two_digits_zero_padded(low)]
293 }
294}
295
296#[inline]
300pub(crate) const fn four_to_six_digits(n: ru32<0, 999_999>) -> [&'static str; 3] {
301 let n = n.get();
302
303 let (first_two, remaining) = (n / 10_000, n % 10_000);
304
305 let size = 2 - (first_two < 10) as usize - (first_two == 0) as usize;
306 let offset = first_two as usize * 2 + 2 - size;
307
308 let first_two = unsafe { str_from_raw_parts(ZERO_PADDED_PAIRS.as_ptr().add(offset), size) };
311 let [second_two, last_two] =
313 four_digits_zero_padded(unsafe { ru16::new_unchecked(remaining as u16) });
314 [first_two, second_two, last_two]
315}
316
317#[inline]
321#[cfg(feature = "formatting")]
322pub(crate) const fn five_digits_zero_padded(n: ru32<0, 99_999>) -> [&'static str; 3] {
323 let n = n.get();
324
325 let (first_one, remaining) = (n / 10_000, n % 10_000);
326
327 let first_one = single_digit(unsafe { ru8::new_unchecked(first_one as u8) });
329 let [second_two, last_two] =
331 four_digits_zero_padded(unsafe { ru16::new_unchecked(remaining as u16) });
332 [first_one, second_two, last_two]
333}
334
335#[inline]
338#[cfg(feature = "formatting")]
339pub(crate) const fn six_digits_zero_padded(n: ru32<0, 999_999>) -> [&'static str; 3] {
340 let n = n.get();
341
342 let (first_two, remaining) = (n / 10_000, n % 10_000);
343
344 let first_two = two_digits_zero_padded(unsafe { ru8::new_unchecked(first_two as u8) });
346 let [second_two, last_two] =
348 four_digits_zero_padded(unsafe { ru16::new_unchecked(remaining as u16) });
349 [first_two, second_two, last_two]
350}
351
352#[inline]
358pub(crate) const fn subsecond_from_nanos(n: ru32<0, 999_999_999>) -> [&'static str; 5] {
359 let n = n.get();
360 let (digits_1_thru_5, digits_6_thru_9) = (n / 10_000, n % 10_000);
361 let (digit_1, digits_2_thru_5) = (digits_1_thru_5 / 10_000, digits_1_thru_5 % 10_000);
362
363 unsafe {
366 let digit_1 = single_digit(ru8::new_unchecked(digit_1 as u8));
367 let [digits_2_and_3, digits_4_and_5] =
368 four_digits_zero_padded(ru16::new_unchecked(digits_2_thru_5 as u16));
369 let [digits_6_and_7, digits_8_and_9] =
370 four_digits_zero_padded(ru16::new_unchecked(digits_6_thru_9 as u16));
371
372 [
373 digit_1,
374 digits_2_and_3,
375 digits_4_and_5,
376 digits_6_and_7,
377 digits_8_and_9,
378 ]
379 }
380}
381
382#[inline]
387pub(crate) const fn truncated_subsecond_from_nanos(n: ru32<0, 999_999_999>) -> StackStr<9> {
388 #[repr(C, align(8))]
389 #[derive(Clone, Copy)]
390 struct Digits {
391 _padding: MaybeUninit<[u8; 7]>,
392 digit_1: u8,
393 digits_2_thru_9: [u8; 8],
394 }
395
396 let [
397 digit_1,
398 digits_2_and_3,
399 digits_4_and_5,
400 digits_6_and_7,
401 digits_8_and_9,
402 ] = subsecond_from_nanos(n);
403
404 let buf = Digits {
407 _padding: MaybeUninit::uninit(),
408 digit_1: digit_1.as_bytes()[0],
409 digits_2_thru_9: [
410 digits_2_and_3.as_bytes()[0],
411 digits_2_and_3.as_bytes()[1],
412 digits_4_and_5.as_bytes()[0],
413 digits_4_and_5.as_bytes()[1],
414 digits_6_and_7.as_bytes()[0],
415 digits_6_and_7.as_bytes()[1],
416 digits_8_and_9.as_bytes()[0],
417 digits_8_and_9.as_bytes()[1],
418 ],
419 };
420
421 let bitmask = u64::from_le_bytes(buf.digits_2_thru_9) ^ u64::from_le_bytes([b'0'; 8]);
425 let digits_to_truncate = bitmask.leading_zeros() / 8;
426 let len = 9 - digits_to_truncate as usize;
427
428 unsafe {
432 StackStr::new(
433 *(&raw const buf)
434 .byte_add(core::mem::offset_of!(Digits, digit_1))
435 .cast(),
436 len,
437 )
438 }
439}
440
441#[inline]
443pub(crate) const fn u64_pad_none(value: u64) -> StackTrailingStr<20> {
444 let mut bytes = [MaybeUninit::uninit(); 20];
445
446 let mut offset = 20;
447 let mut remain = value;
448
449 while remain > 999 {
450 offset -= 4;
451 let quad = remain % 1_00_00;
452 remain /= 1_00_00;
453 let [pair1, pair2] = div_100(unsafe { ru16::new_unchecked(quad as u16) });
455 unsafe {
457 write_two_digits(&mut bytes, offset, pair1);
458 write_two_digits(&mut bytes, offset + 2, pair2);
459 }
460 }
461
462 if remain > 9 {
463 offset -= 2;
464
465 let [last, pair] = div_100(unsafe { ru16::new_unchecked(remain as u16) });
467 remain = last.get() as u64;
468 unsafe { write_two_digits(&mut bytes, offset, pair) };
470 }
471
472 if remain != 0 || value == 0 {
473 offset -= 1;
474
475 let last = remain as u8 & 15;
476 unsafe { write_one_digit(&mut bytes, offset, ru8::new_unchecked(last)) };
479 }
480
481 unsafe { StackTrailingStr::new(bytes, offset) }
483}
484
485#[inline]
487#[cfg(feature = "formatting")]
488pub(crate) const fn u128_pad_none(value: u128) -> StackTrailingStr<39> {
489 let mut bytes = [MaybeUninit::uninit(); 39];
490
491 let (quot_1e16, mod_1e16) = div_rem_1e16(value);
493 let (mut remain, mut offset) = if quot_1e16 == 0 {
494 (mod_1e16.get(), 39)
495 } else {
496 unsafe { enc_16lsd::<23>(&mut bytes, mod_1e16) };
499
500 let (quot2, mod2) = div_rem_1e16(quot_1e16);
502 if quot2 == 0 {
503 (mod2.get(), 23)
504 } else {
505 unsafe { enc_16lsd::<7>(&mut bytes, mod2) };
508 (quot2 as u64, 7)
510 }
511 };
512
513 while remain > 999 {
515 offset -= 4;
516
517 let quad = remain % 1_00_00;
519 remain /= 1_00_00;
520 let [pair1, pair2] = div_100(unsafe { ru16::new_unchecked(quad as u16) });
522 unsafe {
524 write_two_digits(&mut bytes, offset, pair1);
525 write_two_digits(&mut bytes, offset + 2, pair2);
526 }
527 }
528
529 if remain > 9 {
531 offset -= 2;
532
533 let [last, pair] = div_100(unsafe { ru16::new_unchecked(remain as u16) });
535 remain = last.get() as u64;
536 unsafe { write_two_digits(&mut bytes, offset, pair) };
538 }
539
540 if remain != 0 || value == 0 {
542 offset -= 1;
543
544 let last = remain as u8 & 15;
546 unsafe { write_one_digit(&mut bytes, offset, ru8::new_unchecked(last)) };
549 }
550
551 unsafe { StackTrailingStr::new(bytes, offset) }
553}
554
555#[cfg(feature = "formatting")]
561const unsafe fn enc_16lsd<const OFFSET: usize>(
562 buf: &mut [MaybeUninit<u8>],
563 n: ru64<0, 9999_9999_9999_9999>,
564) {
565 let mut remain = n.get();
567
568 let mut quad_index = 3;
569 while quad_index >= 1 {
570 let quad = remain % 1_00_00;
571 remain /= 1_00_00;
572 let [pair1, pair2] = div_100(unsafe { ru16::new_unchecked(quad as u16) });
574 unsafe {
576 write_two_digits(buf, quad_index * 4 + OFFSET, pair1);
577 write_two_digits(buf, quad_index * 4 + OFFSET + 2, pair2);
578 }
579 quad_index -= 1;
580 }
581
582 let [pair1, pair2] = div_100(unsafe { ru16::new_unchecked(remain as u16) });
585 unsafe {
587 write_two_digits(buf, OFFSET, pair1);
588 write_two_digits(buf, OFFSET + 2, pair2);
589 }
590}
591
592#[cfg(feature = "formatting")]
595const fn div_rem_1e16(n: u128) -> (u128, ru64<0, 9999_9999_9999_9999>) {
596 const D: u128 = 1_0000_0000_0000_0000;
597 if n < D {
598 return (0, unsafe { ru64::new_unchecked(n as u64) });
600 }
601
602 const M_HIGH: u128 = 76_624_777_043_294_442_917_917_351_357_515_459_181;
603 const SH_POST: u8 = 51;
604
605 let quot = mulhi(n, M_HIGH) >> SH_POST;
607 let rem = n - quot * D;
608 (quot, unsafe { ru64::new_unchecked(rem as u64) })
610}
611
612#[inline]
614#[cfg(feature = "formatting")]
615const fn mulhi(x: u128, y: u128) -> u128 {
616 let x_lo = x as u64;
617 let x_hi = (x >> 64) as u64;
618 let y_lo = y as u64;
619 let y_hi = (y >> 64) as u64;
620
621 let carry = (x_lo as u128 * y_lo as u128) >> 64;
623 let m = x_lo as u128 * y_hi as u128 + carry;
624 let high1 = m >> 64;
625
626 let m_lo = m as u64;
627 let high2 = (x_hi as u128 * y_lo as u128 + m_lo as u128) >> 64;
628
629 x_hi as u128 * y_hi as u128 + high1 + high2
630}