Skip to main content

time/
num_fmt.rs

1//! Formatting utilities for numbers.
2//!
3//! These functions are low-level, but are designed to be _extremely_ fast for their designed use
4//! cases. They have strict requirements, and may not return the most ergonomic types to avoid
5//! unnecessary allocations and copying.
6
7use 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/// A string type with a maximum length known at compile time, stored on the stack.
33///
34/// Note that while the _maximum_ length is known at compile time, the string may be shorter. This
35/// information is stored inline.
36#[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    /// # Safety:
44    ///
45    /// - `buf` must be initialized for at least `len` bytes.
46    /// - The first `len` bytes of `buf` must be valid UTF-8.
47    #[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        // Safety: This type can only be constructed when the caller asserts that the buffer is
60        // valid UTF-8 for the first `len` bytes.
61        unsafe { str_from_raw_parts(self.buf.as_ptr().cast(), self.len) }
62    }
63}
64
65/// A string type with a maximum length known at compile time, stored on the stack.
66///
67/// Note that while the _maximum_ length is known at compile time, the string may be shorter. This
68/// information is stored inline.
69#[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    /// # Safety:
79    ///
80    /// - The last `MAX_LEN - start_index` bytes of `buf` must be initialized and valid UTF-8.
81    #[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        // Safety: This type can only be constructed when the caller asserts that the buffer is
95        // valid UTF-8 for the last `len` bytes.
96        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/// Write a two digit integer to `buf` at `offset` and `offset + 1`.
106///
107/// # Safety
108///
109/// `buf` must be at least `offset + 2` bytes long.
110#[inline]
111#[cfg(feature = "formatting")]
112const unsafe fn write_two_digits(buf: &mut [MaybeUninit<u8>], offset: usize, value: ru8<0, 99>) {
113    // Safety: `buf` is at least `offset + 2` bytes long.
114    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/// Write a single digit integer to `buf` at `offset`.
124///
125/// # Safety
126///
127/// `buf` must be at least `offset` bytes long.
128#[inline]
129#[cfg(feature = "formatting")]
130const unsafe fn write_one_digit(buf: &mut [MaybeUninit<u8>], offset: usize, value: ru8<0, 9>) {
131    // Safety: `buf` is at least `offset` bytes long.
132    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/// # Safety
142///
143/// - `ptr` must be non-null and point to `len` initialized bytes of UTF-8 data.
144/// - `ptr` is valid for (and not mutated during) lifetime `'a`.
145#[inline]
146pub(crate) const unsafe fn str_from_raw_parts<'a>(ptr: *const u8, len: usize) -> &'a str {
147    // Safety: The caller must ensure that `ptr` is valid for `len` bytes and that the bytes are
148    // valid UTF-8. The caller must also ensure that the lifetime `'a` is valid for the returned
149    // string.
150    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; // 19 is faster or equal to 12 even for 3 digits.
156    const SIG: u32 = (1 << EXP) / 100 + 1;
157
158    let n = n.get();
159
160    let high = (n as u32 * SIG) >> EXP; // value / 100
161    let low = n as u32 - high * 100;
162
163    // Safety: `high` is guaranteed to be less than 100 and `low` is guaranteed to be less than 100
164    // due to the arithmetic above.
165    unsafe {
166        [
167            ru8::new_unchecked(high as u8),
168            ru8::new_unchecked(low as u8),
169        ]
170    }
171}
172
173/// Obtain a string containing a single ASCII digit representing `n`.
174#[inline]
175pub(crate) const fn single_digit(n: ru8<0, 9>) -> &'static str {
176    // Safety: We're staying within the bounds of the array. The array contains only ASCII
177    // characters, so it's valid UTF-8.
178    unsafe { str_from_raw_parts(SINGLE_DIGITS.as_ptr().add(n.get() as usize), 1) }
179}
180
181/// Obtain a string of one or two ASCII digits representing `n`. No leading zeros or spaces are
182/// included.
183#[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    // Safety: We're staying within the bounds of the array. The array contains only ASCII
188    // characters, so it's valid UTF-8.
189    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/// Obtain a string of two ASCII digits representing `n`. This includes a leading zero if `n` is
200/// less than 10.
201#[inline]
202pub(crate) const fn two_digits_zero_padded(n: ru8<0, 99>) -> &'static str {
203    // Safety: We're staying within the bounds of the array. The array contains only ASCII
204    // characters, so it's valid UTF-8.
205    unsafe { str_from_raw_parts(ZERO_PADDED_PAIRS.as_ptr().add((n.get() as usize) * 2), 2) }
206}
207
208/// Obtain a string of two ASCII digits representing `n`. This includes a leading space if `n` is
209/// less than 10.
210#[inline]
211#[cfg(feature = "formatting")]
212pub(crate) const fn two_digits_space_padded(n: ru8<0, 99>) -> &'static str {
213    // Safety: We're staying within the bounds of the array. The array contains only ASCII
214    // characters, so it's valid UTF-8.
215    unsafe { str_from_raw_parts(SPACE_PADDED_PAIRS.as_ptr().add((n.get() as usize) * 2), 2) }
216}
217
218/// Obtain two strings of ASCII digits representing `n`. The first string is most significant. No
219/// leading zeros or spaces are included.
220#[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/// Obtain two strings of ASCII digits representing `n`. The first string is the most significant.
232/// Leading zeros are included if the number has fewer than 3 digits.
233#[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        // Safety: `high` is guaranteed to be less than 10 due to the range of the input.
239        single_digit(unsafe { high.narrow_unchecked() }),
240        two_digits_zero_padded(low),
241    ]
242}
243
244/// Obtain two strings of ASCII digits representing `n`. The first string is the most significant.
245/// Leading spaces are included if the number has fewer than 3 digits.
246#[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/// Obtain two strings of ASCII digits representing `n`. The first string is the most significant.
259/// No leading zeros or spaces are included.
260#[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/// Obtain two strings of two ASCII digits each representing `n`. The first string is the most
272/// significant. Leading zeros are included if the number has fewer than 4 digits.
273#[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/// Obtain two strings of two ASCII digits each representing `n`. The first string is the most
280/// significant. Leading spaces are included if the number has fewer than 4 digits.
281#[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/// Obtain three strings which together represent `n`. The first string is the most significant.
294/// Leading zeros are included if the number has fewer than 4 digits. The first string will be empty
295/// if `n` is less than 10,000.
296#[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    // Safety: `offset` is within the bounds of the array. The array contains only ASCII characters,
306    // so it's valid UTF-8.
307    let first_two = unsafe { str_from_raw_parts(ZERO_PADDED_PAIRS.as_ptr().add(offset), size) };
308    // Safety: `remaining` is guaranteed to be less than 10,000 due to the modulus above.
309    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/// Obtain three strings which together represent `n`. The first string is the most significant.
315/// Leading zeros are included if the number has fewer than 5 digits. The first string will be empty
316/// if `n` is less than 10,000.
317#[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    // Safety: `first_one` is guaranteed to be less than 10 due to the division above.
325    let first_one = single_digit(unsafe { ru8::new_unchecked(first_one as u8) });
326    // Safety: `remaining` is guaranteed to be less than 10,000 due to the modulus above.
327    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/// Obtain three strings which together represent `n`. The first string is the most significant.
333/// Leading zeroes are included if the number has fewer than 6 digits.
334#[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    // Safety: `first_two` is guaranteed to be less than 100 due to the division above.
342    let first_two = two_digits_zero_padded(unsafe { ru8::new_unchecked(first_two as u8) });
343    // Safety: `remaining` is guaranteed to be less than 10,000 due to the modulus above.
344    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/// Obtain five strings which together represent `n`, which is a number of nanoseconds.
350///
351/// This value is intended to be used after a decimal point to represent a fractional second. The
352/// first string will always contain exactly one digit; the remaining four will contain two digits
353/// each.
354#[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    // Safety: The type of `n` ensures that `n` is less than 1,000,000,000. Combined with the
361    // arithmetic above, this guarantees that all values are in the required ranges.
362    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/// Obtain a string of 1 to 9 ASCII digits representing `n`, which is a number of nanoseconds.
380///
381/// This value is intended to be used after a decimal point to represent a fractional second.
382/// Trailing zeros are truncated, but at least one digit is always present.
383#[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    // Ensure that digits 2 thru 9 are stored as a single array that is 8-aligned. This allows the
402    // conversion to a `u64` to be zero cost, resulting in a nontrivial performance improvement.
403    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    // By converting the bytes into a single integer, we can effectively perform an equality check
419    // against b'0' for all bytes at once. This is actually faster than using portable SIMD (even
420    // with `-Ctarget-cpu=native`).
421    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    // Safety: All bytes are initialized and valid UTF-8, and `len` represents the number of bytes
426    // we wish to display (that is between 1 and 9 inclusive). `Digits` is `#[repr(C)]`, so the
427    // layout is guaranteed.
428    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/// Format a `u64` into a string with no padding.
439#[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        // Safety: `quad` is guaranteed to be less than 10,000 due to the modulus above.
452        let [pair1, pair2] = div_100(unsafe { ru16::new_unchecked(quad as u16) });
453        // Safety: `buf` is at least `offset + 4` bytes long.
454        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        // Safety: `remain` is guaranteed to be less than 10,000 due to the loop above.
464        let [last, pair] = div_100(unsafe { ru16::new_unchecked(remain as u16) });
465        remain = last.get() as u64;
466        // Safety: `buf` is at least `offset + 2` bytes long.
467        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        // Safety: `offset` is known to be in bounds, and the value is known to be less than 10 due
475        // to the conditionals and bitwise AND above.
476        unsafe { write_one_digit(&mut bytes, offset, ru8::new_unchecked(last)) };
477    }
478
479    // Safety: All bytes starting at `offset` are initialized and valid UTF-8.
480    unsafe { StackTrailingStr::new(bytes, offset) }
481}
482
483/// Format a `u128` into a string with no padding.
484#[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    // Take the 16 least-significant decimals.
490    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        // Write digits at buf[23..39].
495        // Safety: `bytes` is 39 bytes long, so writing at offset 23 for 16 bytes is sound.
496        unsafe { enc_16lsd::<23>(&mut bytes, mod_1e16) };
497
498        // Take another 16 decimals.
499        let (quot2, mod2) = div_rem_1e16(quot_1e16);
500        if quot2 == 0 {
501            (mod2.get(), 23)
502        } else {
503            // Write digits at buf[7..23].
504            // Safety: `bytes` is 39 bytes long, so writing at offset 7 for 16 bytes is sound.
505            unsafe { enc_16lsd::<7>(&mut bytes, mod2) };
506            // Safety: `quot2`` has at most 7 decimals remaining after two 1e16 divisions.
507            (quot2 as u64, 7)
508        }
509    };
510
511    // Format per four digits from the lookup table.
512    while remain > 999 {
513        offset -= 4;
514
515        // pull two pairs
516        let quad = remain % 1_00_00;
517        remain /= 1_00_00;
518        // Safety: `quad` is guaranteed to be less than 10,000 due to the modulus above.
519        let [pair1, pair2] = div_100(unsafe { ru16::new_unchecked(quad as u16) });
520        // Safety: `buf` is at least `offset + 4` bytes long.
521        unsafe {
522            write_two_digits(&mut bytes, offset, pair1);
523            write_two_digits(&mut bytes, offset + 2, pair2);
524        }
525    }
526
527    // Format per two digits from the lookup table.
528    if remain > 9 {
529        offset -= 2;
530
531        // Safety: `remain` is guaranteed to be less than 10,000 due to the loop above.
532        let [last, pair] = div_100(unsafe { ru16::new_unchecked(remain as u16) });
533        remain = last.get() as u64;
534        // Safety: `buf` is at least `offset + 2` bytes long.
535        unsafe { write_two_digits(&mut bytes, offset, pair) };
536    }
537
538    // Format the last remaining digit, if any.
539    if remain != 0 || value == 0 {
540        offset -= 1;
541
542        // Either the compiler sees that remain < 10, or it prevents a boundary check up next.
543        let last = remain as u8 & 15;
544        // Safety: `offset` is known to be in bounds, and the value is known to be less than 10 due
545        // to the conditionals and bitwise AND above.
546        unsafe { write_one_digit(&mut bytes, offset, ru8::new_unchecked(last)) };
547    }
548
549    // Safety: All bytes starting at `offset` are initialized and valid UTF-8.
550    unsafe { StackTrailingStr::new(bytes, offset) }
551}
552
553/// Encodes the 16 least-significant decimals of n into `buf[OFFSET..OFFSET + 16]`.
554///
555/// # Safety
556///
557/// - `buf` must be at least `OFFSET + 16` bytes long.
558#[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    // Consume the least-significant decimals from a working copy.
564    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        // Safety: `quad` is guaranteed to be less than 10,000 due to the modulus above.
571        let [pair1, pair2] = div_100(unsafe { ru16::new_unchecked(quad as u16) });
572        // Safety: `buf` is at least `quad_index * 4 + OFFSET + 4` bytes long.
573        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    // Safety: `remain` is guaranteed to be less than 10,000 due the range of `n` and the arithmetic
581    // in the loop above.
582    let [pair1, pair2] = div_100(unsafe { ru16::new_unchecked(remain as u16) });
583    // Safety: `buf` is at least `OFFSET + 4` bytes long.
584    unsafe {
585        write_two_digits(buf, OFFSET, pair1);
586        write_two_digits(buf, OFFSET + 2, pair2);
587    }
588}
589
590// Euclidean division plus remainder with constant 1e16 basically consumes 16
591// decimals from n.
592#[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        // Safety: We just checked that `n` is in range.
597        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    // n.widening_mul(M_HIGH).1 >> SH_POST
604    let quot = mulhi(n, M_HIGH) >> SH_POST;
605    let rem = n - quot * D;
606    // Safety: The arithmetic above ensures that `rem` is in range.
607    (quot, unsafe { ru64::new_unchecked(rem as u64) })
608}
609
610/// Multiply unsigned 128 bit integers, return upper 128 bits of the result
611#[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    // handle possibility of overflow
620    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}