1use core::mem::MaybeUninit;
8use core::ops::Deref;
9#[cfg(feature = "formatting")]
10use core::ptr;
11use core::slice;
12
13#[cfg(feature = "formatting")]
14use deranged::ru64;
15use deranged::{ru8, ru16, ru32};
16
17static SINGLE_DIGITS: [u8; 10] = *b"0123456789";
18
19static ZERO_PADDED_PAIRS: [u8; 200] = *b"0001020304050607080910111213141516171819\
20 2021222324252627282930313233343536373839\
21 4041424344454647484950515253545556575859\
22 6061626364656667686970717273747576777879\
23 8081828384858687888990919293949596979899";
24
25#[cfg(feature = "formatting")]
26static SPACE_PADDED_PAIRS: [u8; 200] = *b" 0 1 2 3 4 5 6 7 8 910111213141516171819\
27 2021222324252627282930313233343536373839\
28 4041424344454647484950515253545556575859\
29 6061626364656667686970717273747576777879\
30 8081828384858687888990919293949596979899";
31
32#[derive(Clone, Copy)]
37pub(crate) struct StackStr<const MAX_LEN: usize> {
38 buf: [MaybeUninit<u8>; MAX_LEN],
39 len: usize,
40}
41
42impl<const MAX_LEN: usize> StackStr<MAX_LEN> {
43 #[inline]
48 pub(crate) const unsafe fn new(buf: [MaybeUninit<u8>; MAX_LEN], len: usize) -> Self {
49 debug_assert!(len <= MAX_LEN);
50 Self { buf, len }
51 }
52}
53
54impl<const MAX_LEN: usize> Deref for StackStr<MAX_LEN> {
55 type Target = str;
56
57 #[inline]
58 fn deref(&self) -> &Self::Target {
59 unsafe { str_from_raw_parts(self.buf.as_ptr().cast(), self.len) }
62 }
63}
64
65#[cfg(feature = "formatting")]
70#[derive(Clone, Copy)]
71pub(crate) struct StackTrailingStr<const MAX_LEN: usize> {
72 buf: [MaybeUninit<u8>; MAX_LEN],
73 start_index: usize,
74}
75
76#[cfg(feature = "formatting")]
77impl<const MAX_LEN: usize> StackTrailingStr<MAX_LEN> {
78 #[inline]
82 pub(crate) const unsafe fn new(buf: [MaybeUninit<u8>; MAX_LEN], start_index: usize) -> Self {
83 debug_assert!(start_index <= MAX_LEN);
84 Self { buf, start_index }
85 }
86}
87
88#[cfg(feature = "formatting")]
89impl<const MAX_LEN: usize> Deref for StackTrailingStr<MAX_LEN> {
90 type Target = str;
91
92 #[inline]
93 fn deref(&self) -> &Self::Target {
94 unsafe {
97 str_from_raw_parts(
98 self.buf.as_ptr().add(self.start_index).cast(),
99 MAX_LEN - self.start_index,
100 )
101 }
102 }
103}
104
105#[inline]
111#[cfg(feature = "formatting")]
112const unsafe fn write_two_digits(buf: &mut [MaybeUninit<u8>], offset: usize, value: ru8<0, 99>) {
113 unsafe {
115 ptr::copy_nonoverlapping(
116 two_digits_zero_padded(value).as_ptr().cast(),
117 buf.as_mut_ptr().add(offset),
118 2,
119 );
120 }
121}
122
123#[inline]
129#[cfg(feature = "formatting")]
130const unsafe fn write_one_digit(buf: &mut [MaybeUninit<u8>], offset: usize, value: ru8<0, 9>) {
131 unsafe {
133 ptr::copy_nonoverlapping(
134 single_digit(value).as_ptr().cast(),
135 buf.as_mut_ptr().add(offset),
136 1,
137 );
138 }
139}
140
141#[inline]
146pub(crate) const unsafe fn str_from_raw_parts<'a>(ptr: *const u8, len: usize) -> &'a str {
147 unsafe { str::from_utf8_unchecked(slice::from_raw_parts(ptr, len)) }
151}
152
153#[inline]
154const fn div_100(n: ru16<0, 9_999>) -> [ru8<0, 99>; 2] {
155 const EXP: u32 = 19; const SIG: u32 = (1 << EXP) / 100 + 1;
157
158 let n = n.get();
159
160 let high = (n as u32 * SIG) >> EXP; let low = n as u32 - high * 100;
162
163 unsafe {
166 [
167 ru8::new_unchecked(high as u8),
168 ru8::new_unchecked(low as u8),
169 ]
170 }
171}
172
173#[inline]
175pub(crate) const fn single_digit(n: ru8<0, 9>) -> &'static str {
176 unsafe { str_from_raw_parts(SINGLE_DIGITS.as_ptr().add(n.get() as usize), 1) }
179}
180
181#[inline]
184pub(crate) const fn one_to_two_digits_no_padding(n: ru8<0, 99>) -> &'static str {
185 let n = n.get();
186 let is_single_digit = n < 10;
187 unsafe {
190 str_from_raw_parts(
191 ZERO_PADDED_PAIRS
192 .as_ptr()
193 .add((n as usize) * 2 + is_single_digit as usize),
194 2 - is_single_digit as usize,
195 )
196 }
197}
198
199#[inline]
202pub(crate) const fn two_digits_zero_padded(n: ru8<0, 99>) -> &'static str {
203 unsafe { str_from_raw_parts(ZERO_PADDED_PAIRS.as_ptr().add((n.get() as usize) * 2), 2) }
206}
207
208#[inline]
211#[cfg(feature = "formatting")]
212pub(crate) const fn two_digits_space_padded(n: ru8<0, 99>) -> &'static str {
213 unsafe { str_from_raw_parts(SPACE_PADDED_PAIRS.as_ptr().add((n.get() as usize) * 2), 2) }
216}
217
218#[inline]
221#[cfg(feature = "formatting")]
222pub(crate) fn one_to_three_digits_no_padding(n: ru16<0, 999>) -> [&'static str; 2] {
223 if let Some(n) = n.narrow::<0, 99>() {
224 crate::hint::cold_path();
225 ["", one_to_two_digits_no_padding(n.into())]
226 } else {
227 three_digits_zero_padded(n)
228 }
229}
230
231#[inline]
234#[cfg(feature = "formatting")]
235pub(crate) const fn three_digits_zero_padded(n: ru16<0, 999>) -> [&'static str; 2] {
236 let [high, low] = div_100(n.expand());
237 [
238 single_digit(unsafe { high.narrow_unchecked() }),
240 two_digits_zero_padded(low),
241 ]
242}
243
244#[inline]
247#[cfg(feature = "formatting")]
248pub(crate) const fn three_digits_space_padded(n: ru16<0, 999>) -> [&'static str; 2] {
249 let [high, low] = div_100(n.expand());
250
251 if let Some(high) = high.narrow::<1, 9>() {
252 [single_digit(high.expand()), two_digits_zero_padded(low)]
253 } else {
254 [" ", two_digits_space_padded(low)]
255 }
256}
257
258#[inline]
261#[cfg(feature = "formatting")]
262pub(crate) fn one_to_four_digits_no_padding(n: ru16<0, 9_999>) -> [&'static str; 2] {
263 if let Some(n) = n.narrow::<0, 999>() {
264 crate::hint::cold_path();
265 one_to_three_digits_no_padding(n)
266 } else {
267 four_digits_zero_padded(n)
268 }
269}
270
271#[inline]
274pub(crate) const fn four_digits_zero_padded(n: ru16<0, 9_999>) -> [&'static str; 2] {
275 let [high, low] = div_100(n);
276 [two_digits_zero_padded(high), two_digits_zero_padded(low)]
277}
278
279#[inline]
282#[cfg(feature = "formatting")]
283pub(crate) const fn four_digits_space_padded(n: ru16<0, 9_999>) -> [&'static str; 2] {
284 let [high, low] = div_100(n);
285
286 if high.get() == 0 {
287 [" ", two_digits_space_padded(low)]
288 } else {
289 [two_digits_space_padded(high), two_digits_zero_padded(low)]
290 }
291}
292
293#[inline]
297pub(crate) const fn four_to_six_digits(n: ru32<0, 999_999>) -> [&'static str; 3] {
298 let n = n.get();
299
300 let (first_two, remaining) = (n / 10_000, n % 10_000);
301
302 let size = 2 - (first_two < 10) as usize - (first_two == 0) as usize;
303 let offset = first_two as usize * 2 + 2 - size;
304
305 let first_two = unsafe { str_from_raw_parts(ZERO_PADDED_PAIRS.as_ptr().add(offset), size) };
308 let [second_two, last_two] =
310 four_digits_zero_padded(unsafe { ru16::new_unchecked(remaining as u16) });
311 [first_two, second_two, last_two]
312}
313
314#[inline]
318#[cfg(feature = "formatting")]
319pub(crate) const fn five_digits_zero_padded(n: ru32<0, 99_999>) -> [&'static str; 3] {
320 let n = n.get();
321
322 let (first_one, remaining) = (n / 10_000, n % 10_000);
323
324 let first_one = single_digit(unsafe { ru8::new_unchecked(first_one as u8) });
326 let [second_two, last_two] =
328 four_digits_zero_padded(unsafe { ru16::new_unchecked(remaining as u16) });
329 [first_one, second_two, last_two]
330}
331
332#[inline]
335#[cfg(feature = "formatting")]
336pub(crate) const fn six_digits_zero_padded(n: ru32<0, 999_999>) -> [&'static str; 3] {
337 let n = n.get();
338
339 let (first_two, remaining) = (n / 10_000, n % 10_000);
340
341 let first_two = two_digits_zero_padded(unsafe { ru8::new_unchecked(first_two as u8) });
343 let [second_two, last_two] =
345 four_digits_zero_padded(unsafe { ru16::new_unchecked(remaining as u16) });
346 [first_two, second_two, last_two]
347}
348
349#[inline]
355pub(crate) const fn subsecond_from_nanos(n: ru32<0, 999_999_999>) -> [&'static str; 5] {
356 let n = n.get();
357 let (digits_1_thru_5, digits_6_thru_9) = (n / 10_000, n % 10_000);
358 let (digit_1, digits_2_thru_5) = (digits_1_thru_5 / 10_000, digits_1_thru_5 % 10_000);
359
360 unsafe {
363 let digit_1 = single_digit(ru8::new_unchecked(digit_1 as u8));
364 let [digits_2_and_3, digits_4_and_5] =
365 four_digits_zero_padded(ru16::new_unchecked(digits_2_thru_5 as u16));
366 let [digits_6_and_7, digits_8_and_9] =
367 four_digits_zero_padded(ru16::new_unchecked(digits_6_thru_9 as u16));
368
369 [
370 digit_1,
371 digits_2_and_3,
372 digits_4_and_5,
373 digits_6_and_7,
374 digits_8_and_9,
375 ]
376 }
377}
378
379#[inline]
384pub(crate) const fn truncated_subsecond_from_nanos(n: ru32<0, 999_999_999>) -> StackStr<9> {
385 #[repr(C, align(8))]
386 #[derive(Clone, Copy)]
387 struct Digits {
388 _padding: MaybeUninit<[u8; 7]>,
389 digit_1: u8,
390 digits_2_thru_9: [u8; 8],
391 }
392
393 let [
394 digit_1,
395 digits_2_and_3,
396 digits_4_and_5,
397 digits_6_and_7,
398 digits_8_and_9,
399 ] = subsecond_from_nanos(n);
400
401 let buf = Digits {
404 _padding: MaybeUninit::uninit(),
405 digit_1: digit_1.as_bytes()[0],
406 digits_2_thru_9: [
407 digits_2_and_3.as_bytes()[0],
408 digits_2_and_3.as_bytes()[1],
409 digits_4_and_5.as_bytes()[0],
410 digits_4_and_5.as_bytes()[1],
411 digits_6_and_7.as_bytes()[0],
412 digits_6_and_7.as_bytes()[1],
413 digits_8_and_9.as_bytes()[0],
414 digits_8_and_9.as_bytes()[1],
415 ],
416 };
417
418 let bitmask = u64::from_le_bytes(buf.digits_2_thru_9) ^ u64::from_le_bytes([b'0'; 8]);
422 let digits_to_truncate = bitmask.leading_zeros() / 8;
423 let len = 9 - digits_to_truncate as usize;
424
425 unsafe {
429 StackStr::new(
430 *(&raw const buf)
431 .byte_add(core::mem::offset_of!(Digits, digit_1))
432 .cast(),
433 len,
434 )
435 }
436}
437
438#[inline]
440#[cfg(feature = "formatting")]
441pub(crate) const fn u64_pad_none(value: u64) -> StackTrailingStr<20> {
442 let mut bytes = [MaybeUninit::uninit(); 20];
443
444 let mut offset = 20;
445 let mut remain = value;
446
447 while remain > 999 {
448 offset -= 4;
449 let quad = remain % 1_00_00;
450 remain /= 1_00_00;
451 let [pair1, pair2] = div_100(unsafe { ru16::new_unchecked(quad as u16) });
453 unsafe {
455 write_two_digits(&mut bytes, offset, pair1);
456 write_two_digits(&mut bytes, offset + 2, pair2);
457 }
458 }
459
460 if remain > 9 {
461 offset -= 2;
462
463 let [last, pair] = div_100(unsafe { ru16::new_unchecked(remain as u16) });
465 remain = last.get() as u64;
466 unsafe { write_two_digits(&mut bytes, offset, pair) };
468 }
469
470 if remain != 0 || value == 0 {
471 offset -= 1;
472
473 let last = remain as u8 & 15;
474 unsafe { write_one_digit(&mut bytes, offset, ru8::new_unchecked(last)) };
477 }
478
479 unsafe { StackTrailingStr::new(bytes, offset) }
481}
482
483#[inline]
485#[cfg(feature = "formatting")]
486pub(crate) const fn u128_pad_none(value: u128) -> StackTrailingStr<39> {
487 let mut bytes = [MaybeUninit::uninit(); 39];
488
489 let (quot_1e16, mod_1e16) = div_rem_1e16(value);
491 let (mut remain, mut offset) = if quot_1e16 == 0 {
492 (mod_1e16.get(), 39)
493 } else {
494 unsafe { enc_16lsd::<23>(&mut bytes, mod_1e16) };
497
498 let (quot2, mod2) = div_rem_1e16(quot_1e16);
500 if quot2 == 0 {
501 (mod2.get(), 23)
502 } else {
503 unsafe { enc_16lsd::<7>(&mut bytes, mod2) };
506 (quot2 as u64, 7)
508 }
509 };
510
511 while remain > 999 {
513 offset -= 4;
514
515 let quad = remain % 1_00_00;
517 remain /= 1_00_00;
518 let [pair1, pair2] = div_100(unsafe { ru16::new_unchecked(quad as u16) });
520 unsafe {
522 write_two_digits(&mut bytes, offset, pair1);
523 write_two_digits(&mut bytes, offset + 2, pair2);
524 }
525 }
526
527 if remain > 9 {
529 offset -= 2;
530
531 let [last, pair] = div_100(unsafe { ru16::new_unchecked(remain as u16) });
533 remain = last.get() as u64;
534 unsafe { write_two_digits(&mut bytes, offset, pair) };
536 }
537
538 if remain != 0 || value == 0 {
540 offset -= 1;
541
542 let last = remain as u8 & 15;
544 unsafe { write_one_digit(&mut bytes, offset, ru8::new_unchecked(last)) };
547 }
548
549 unsafe { StackTrailingStr::new(bytes, offset) }
551}
552
553#[cfg(feature = "formatting")]
559const unsafe fn enc_16lsd<const OFFSET: usize>(
560 buf: &mut [MaybeUninit<u8>],
561 n: ru64<0, 9999_9999_9999_9999>,
562) {
563 let mut remain = n.get();
565
566 let mut quad_index = 3;
567 while quad_index >= 1 {
568 let quad = remain % 1_00_00;
569 remain /= 1_00_00;
570 let [pair1, pair2] = div_100(unsafe { ru16::new_unchecked(quad as u16) });
572 unsafe {
574 write_two_digits(buf, quad_index * 4 + OFFSET, pair1);
575 write_two_digits(buf, quad_index * 4 + OFFSET + 2, pair2);
576 }
577 quad_index -= 1;
578 }
579
580 let [pair1, pair2] = div_100(unsafe { ru16::new_unchecked(remain as u16) });
583 unsafe {
585 write_two_digits(buf, OFFSET, pair1);
586 write_two_digits(buf, OFFSET + 2, pair2);
587 }
588}
589
590#[cfg(feature = "formatting")]
593const fn div_rem_1e16(n: u128) -> (u128, ru64<0, 9999_9999_9999_9999>) {
594 const D: u128 = 1_0000_0000_0000_0000;
595 if n < D {
596 return (0, unsafe { ru64::new_unchecked(n as u64) });
598 }
599
600 const M_HIGH: u128 = 76_624_777_043_294_442_917_917_351_357_515_459_181;
601 const SH_POST: u8 = 51;
602
603 let quot = mulhi(n, M_HIGH) >> SH_POST;
605 let rem = n - quot * D;
606 (quot, unsafe { ru64::new_unchecked(rem as u64) })
608}
609
610#[inline]
612#[cfg(feature = "formatting")]
613const fn mulhi(x: u128, y: u128) -> u128 {
614 let x_lo = x as u64;
615 let x_hi = (x >> 64) as u64;
616 let y_lo = y as u64;
617 let y_hi = (y >> 64) as u64;
618
619 let carry = (x_lo as u128 * y_lo as u128) >> 64;
621 let m = x_lo as u128 * y_hi as u128 + carry;
622 let high1 = m >> 64;
623
624 let m_lo = m as u64;
625 let high2 = (x_hi as u128 * y_lo as u128 + m_lo as u128) >> 64;
626
627 x_hi as u128 * y_hi as u128 + high1 + high2
628}