core/fmt/
num.rs

1//! Integer and floating-point number formatting
2
3use crate::fmt::NumBuffer;
4use crate::mem::MaybeUninit;
5use crate::num::fmt as numfmt;
6use crate::{fmt, ptr, slice, str};
7
8/// Formatting of integers with a non-decimal radix.
9macro_rules! radix_integer {
10    (fmt::$Trait:ident for $Signed:ident and $Unsigned:ident, $prefix:literal, $dig_tab:literal) => {
11        #[stable(feature = "rust1", since = "1.0.0")]
12        impl fmt::$Trait for $Unsigned {
13            /// Format unsigned integers in the radix.
14            fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
15                // Check macro arguments at compile time.
16                const {
17                    assert!($Unsigned::MIN == 0, "need unsigned");
18                    assert!($dig_tab.is_ascii(), "need single-byte entries");
19                }
20
21                // ASCII digits in ascending order are used as a lookup table.
22                const DIG_TAB: &[u8] = $dig_tab;
23                const BASE: $Unsigned = DIG_TAB.len() as $Unsigned;
24                const MAX_DIG_N: usize = $Unsigned::MAX.ilog(BASE) as usize + 1;
25
26                // Buffer digits of self with right alignment.
27                let mut buf = [MaybeUninit::<u8>::uninit(); MAX_DIG_N];
28                // Count the number of bytes in buf that are not initialized.
29                let mut offset = buf.len();
30
31                // Accumulate each digit of the number from the least
32                // significant to the most significant figure.
33                let mut remain = *self;
34                loop {
35                    let digit = remain % BASE;
36                    remain /= BASE;
37
38                    offset -= 1;
39                    // SAFETY: `remain` will reach 0 and we will break before `offset` wraps
40                    unsafe { core::hint::assert_unchecked(offset < buf.len()) }
41                    buf[offset].write(DIG_TAB[digit as usize]);
42                    if remain == 0 {
43                        break;
44                    }
45                }
46
47                // SAFETY: Starting from `offset`, all elements of the slice have been set.
48                let digits = unsafe { slice_buffer_to_str(&buf, offset) };
49                f.pad_integral(true, $prefix, digits)
50            }
51        }
52
53        #[stable(feature = "rust1", since = "1.0.0")]
54        impl fmt::$Trait for $Signed {
55            /// Format signed integers in the two’s-complement form.
56            fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
57                fmt::$Trait::fmt(&self.cast_unsigned(), f)
58            }
59        }
60    };
61}
62
63/// Formatting of integers with a non-decimal radix.
64macro_rules! radix_integers {
65    ($Signed:ident, $Unsigned:ident) => {
66        radix_integer! { fmt::Binary   for $Signed and $Unsigned, "0b", b"01" }
67        radix_integer! { fmt::Octal    for $Signed and $Unsigned, "0o", b"01234567" }
68        radix_integer! { fmt::LowerHex for $Signed and $Unsigned, "0x", b"0123456789abcdef" }
69        radix_integer! { fmt::UpperHex for $Signed and $Unsigned, "0x", b"0123456789ABCDEF" }
70    };
71}
72radix_integers! { isize, usize }
73radix_integers! { i8, u8 }
74radix_integers! { i16, u16 }
75radix_integers! { i32, u32 }
76radix_integers! { i64, u64 }
77radix_integers! { i128, u128 }
78
79macro_rules! impl_Debug {
80    ($($T:ident)*) => {
81        $(
82            #[stable(feature = "rust1", since = "1.0.0")]
83            impl fmt::Debug for $T {
84                #[inline]
85                fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
86                    if f.debug_lower_hex() {
87                        fmt::LowerHex::fmt(self, f)
88                    } else if f.debug_upper_hex() {
89                        fmt::UpperHex::fmt(self, f)
90                    } else {
91                        fmt::Display::fmt(self, f)
92                    }
93                }
94            }
95        )*
96    };
97}
98
99// 2 digit decimal look up table
100static DEC_DIGITS_LUT: &[u8; 200] = b"\
101      0001020304050607080910111213141516171819\
102      2021222324252627282930313233343536373839\
103      4041424344454647484950515253545556575859\
104      6061626364656667686970717273747576777879\
105      8081828384858687888990919293949596979899";
106
107/// This function converts a slice of ascii characters into a `&str` starting from `offset`.
108///
109/// # Safety
110///
111/// `buf` content starting from `offset` index MUST BE initialized and MUST BE ascii
112/// characters.
113unsafe fn slice_buffer_to_str(buf: &[MaybeUninit<u8>], offset: usize) -> &str {
114    // SAFETY: `offset` is always included between 0 and `buf`'s length.
115    let written = unsafe { buf.get_unchecked(offset..) };
116    // SAFETY: (`assume_init_ref`) All buf content since offset is set.
117    // SAFETY: (`from_utf8_unchecked`) Writes use ASCII from the lookup table exclusively.
118    unsafe { str::from_utf8_unchecked(written.assume_init_ref()) }
119}
120
121macro_rules! impl_Display {
122    ($($Signed:ident, $Unsigned:ident),* ; as $T:ident into $fmt_fn:ident) => {
123
124        $(
125        const _: () = {
126            assert!($Signed::BITS <= $T::BITS, "need lossless conversion");
127            assert!($Unsigned::BITS <= $T::BITS, "need lossless conversion");
128        };
129
130        #[stable(feature = "rust1", since = "1.0.0")]
131        impl fmt::Display for $Unsigned {
132            fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
133                #[cfg(not(feature = "optimize_for_size"))]
134                {
135                    const MAX_DEC_N: usize = $Unsigned::MAX.ilog10() as usize + 1;
136                    // Buffer decimals for self with right alignment.
137                    let mut buf = [MaybeUninit::<u8>::uninit(); MAX_DEC_N];
138
139                    // SAFETY: `buf` is always big enough to contain all the digits.
140                    unsafe { f.pad_integral(true, "", self._fmt(&mut buf)) }
141                }
142                #[cfg(feature = "optimize_for_size")]
143                {
144                    // Lossless conversion (with as) is asserted at the top of
145                    // this macro.
146                    ${concat($fmt_fn, _small)}(*self as $T, true, f)
147                }
148            }
149        }
150
151        #[stable(feature = "rust1", since = "1.0.0")]
152        impl fmt::Display for $Signed {
153            fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
154                #[cfg(not(feature = "optimize_for_size"))]
155                {
156                    const MAX_DEC_N: usize = $Unsigned::MAX.ilog10() as usize + 1;
157                    // Buffer decimals for self with right alignment.
158                    let mut buf = [MaybeUninit::<u8>::uninit(); MAX_DEC_N];
159
160                    // SAFETY: `buf` is always big enough to contain all the digits.
161                    unsafe { f.pad_integral(*self >= 0, "", self.unsigned_abs()._fmt(&mut buf)) }
162                }
163                #[cfg(feature = "optimize_for_size")]
164                {
165                    // Lossless conversion (with as) is asserted at the top of
166                    // this macro.
167                    return ${concat($fmt_fn, _small)}(self.unsigned_abs() as $T, *self >= 0, f);
168                }
169            }
170        }
171
172        #[cfg(not(feature = "optimize_for_size"))]
173        impl $Unsigned {
174            #[doc(hidden)]
175            #[unstable(
176                feature = "fmt_internals",
177                reason = "specialized method meant to only be used by `SpecToString` implementation",
178                issue = "none"
179            )]
180            pub unsafe fn _fmt<'a>(self, buf: &'a mut [MaybeUninit::<u8>]) -> &'a str {
181                // SAFETY: `buf` will always be big enough to contain all digits.
182                let offset = unsafe { self._fmt_inner(buf) };
183                // SAFETY: Starting from `offset`, all elements of the slice have been set.
184                unsafe { slice_buffer_to_str(buf, offset) }
185            }
186
187            unsafe fn _fmt_inner(self, buf: &mut [MaybeUninit::<u8>]) -> usize {
188                // Count the number of bytes in buf that are not initialized.
189                let mut offset = buf.len();
190                // Consume the least-significant decimals from a working copy.
191                let mut remain = self;
192
193                // Format per four digits from the lookup table.
194                // Four digits need a 16-bit $Unsigned or wider.
195                while size_of::<Self>() > 1 && remain > 999.try_into().expect("branch is not hit for types that cannot fit 999 (u8)") {
196                    // SAFETY: All of the decimals fit in buf due to MAX_DEC_N
197                    // and the while condition ensures at least 4 more decimals.
198                    unsafe { core::hint::assert_unchecked(offset >= 4) }
199                    // SAFETY: The offset counts down from its initial buf.len()
200                    // without underflow due to the previous precondition.
201                    unsafe { core::hint::assert_unchecked(offset <= buf.len()) }
202                    offset -= 4;
203
204                    // pull two pairs
205                    let scale: Self = 1_00_00.try_into().expect("branch is not hit for types that cannot fit 1E4 (u8)");
206                    let quad = remain % scale;
207                    remain /= scale;
208                    let pair1 = (quad / 100) as usize;
209                    let pair2 = (quad % 100) as usize;
210                    buf[offset + 0].write(DEC_DIGITS_LUT[pair1 * 2 + 0]);
211                    buf[offset + 1].write(DEC_DIGITS_LUT[pair1 * 2 + 1]);
212                    buf[offset + 2].write(DEC_DIGITS_LUT[pair2 * 2 + 0]);
213                    buf[offset + 3].write(DEC_DIGITS_LUT[pair2 * 2 + 1]);
214                }
215
216                // Format per two digits from the lookup table.
217                if remain > 9 {
218                    // SAFETY: All of the decimals fit in buf due to MAX_DEC_N
219                    // and the if condition ensures at least 2 more decimals.
220                    unsafe { core::hint::assert_unchecked(offset >= 2) }
221                    // SAFETY: The offset counts down from its initial buf.len()
222                    // without underflow due to the previous precondition.
223                    unsafe { core::hint::assert_unchecked(offset <= buf.len()) }
224                    offset -= 2;
225
226                    let pair = (remain % 100) as usize;
227                    remain /= 100;
228                    buf[offset + 0].write(DEC_DIGITS_LUT[pair * 2 + 0]);
229                    buf[offset + 1].write(DEC_DIGITS_LUT[pair * 2 + 1]);
230                }
231
232                // Format the last remaining digit, if any.
233                if remain != 0 || self == 0 {
234                    // SAFETY: All of the decimals fit in buf due to MAX_DEC_N
235                    // and the if condition ensures (at least) 1 more decimals.
236                    unsafe { core::hint::assert_unchecked(offset >= 1) }
237                    // SAFETY: The offset counts down from its initial buf.len()
238                    // without underflow due to the previous precondition.
239                    unsafe { core::hint::assert_unchecked(offset <= buf.len()) }
240                    offset -= 1;
241
242                    // Either the compiler sees that remain < 10, or it prevents
243                    // a boundary check up next.
244                    let last = (remain & 15) as usize;
245                    buf[offset].write(DEC_DIGITS_LUT[last * 2 + 1]);
246                    // not used: remain = 0;
247                }
248
249                offset
250            }
251        }
252
253        impl $Signed {
254            /// Allows users to write an integer (in signed decimal format) into a variable `buf` of
255            /// type [`NumBuffer`] that is passed by the caller by mutable reference.
256            ///
257            /// # Examples
258            ///
259            /// ```
260            /// #![feature(int_format_into)]
261            /// use core::fmt::NumBuffer;
262            ///
263            #[doc = concat!("let n = 0", stringify!($Signed), ";")]
264            /// let mut buf = NumBuffer::new();
265            /// assert_eq!(n.format_into(&mut buf), "0");
266            ///
267            #[doc = concat!("let n1 = 32", stringify!($Signed), ";")]
268            /// assert_eq!(n1.format_into(&mut buf), "32");
269            ///
270            #[doc = concat!("let n2 = ", stringify!($Signed::MAX), ";")]
271            #[doc = concat!("assert_eq!(n2.format_into(&mut buf), ", stringify!($Signed::MAX), ".to_string());")]
272            /// ```
273            #[unstable(feature = "int_format_into", issue = "138215")]
274            pub fn format_into(self, buf: &mut NumBuffer<Self>) -> &str {
275                let mut offset;
276
277                #[cfg(not(feature = "optimize_for_size"))]
278                // SAFETY: `buf` will always be big enough to contain all digits.
279                unsafe {
280                    offset = self.unsigned_abs()._fmt_inner(&mut buf.buf);
281                }
282                #[cfg(feature = "optimize_for_size")]
283                {
284                    // Lossless conversion (with as) is asserted at the top of
285                    // this macro.
286                    offset = ${concat($fmt_fn, _in_buf_small)}(self.unsigned_abs() as $T, &mut buf.buf);
287                }
288                // Only difference between signed and unsigned are these 4 lines.
289                if self < 0 {
290                    offset -= 1;
291                    buf.buf[offset].write(b'-');
292                }
293                // SAFETY: Starting from `offset`, all elements of the slice have been set.
294                unsafe { slice_buffer_to_str(&buf.buf, offset) }
295            }
296        }
297
298        impl $Unsigned {
299            /// Allows users to write an integer (in signed decimal format) into a variable `buf` of
300            /// type [`NumBuffer`] that is passed by the caller by mutable reference.
301            ///
302            /// # Examples
303            ///
304            /// ```
305            /// #![feature(int_format_into)]
306            /// use core::fmt::NumBuffer;
307            ///
308            #[doc = concat!("let n = 0", stringify!($Unsigned), ";")]
309            /// let mut buf = NumBuffer::new();
310            /// assert_eq!(n.format_into(&mut buf), "0");
311            ///
312            #[doc = concat!("let n1 = 32", stringify!($Unsigned), ";")]
313            /// assert_eq!(n1.format_into(&mut buf), "32");
314            ///
315            #[doc = concat!("let n2 = ", stringify!($Unsigned::MAX), ";")]
316            #[doc = concat!("assert_eq!(n2.format_into(&mut buf), ", stringify!($Unsigned::MAX), ".to_string());")]
317            /// ```
318            #[unstable(feature = "int_format_into", issue = "138215")]
319            pub fn format_into(self, buf: &mut NumBuffer<Self>) -> &str {
320                let offset;
321
322                #[cfg(not(feature = "optimize_for_size"))]
323                // SAFETY: `buf` will always be big enough to contain all digits.
324                unsafe {
325                    offset = self._fmt_inner(&mut buf.buf);
326                }
327                #[cfg(feature = "optimize_for_size")]
328                {
329                    // Lossless conversion (with as) is asserted at the top of
330                    // this macro.
331                    offset = ${concat($fmt_fn, _in_buf_small)}(self as $T, &mut buf.buf);
332                }
333                // SAFETY: Starting from `offset`, all elements of the slice have been set.
334                unsafe { slice_buffer_to_str(&buf.buf, offset) }
335            }
336        }
337
338
339        )*
340
341        #[cfg(feature = "optimize_for_size")]
342        fn ${concat($fmt_fn, _in_buf_small)}(mut n: $T, buf: &mut [MaybeUninit::<u8>]) -> usize {
343            let mut curr = buf.len();
344
345            // SAFETY: To show that it's OK to copy into `buf_ptr`, notice that at the beginning
346            // `curr == buf.len() == 39 > log(n)` since `n < 2^128 < 10^39`, and at
347            // each step this is kept the same as `n` is divided. Since `n` is always
348            // non-negative, this means that `curr > 0` so `buf_ptr[curr..curr + 1]`
349            // is safe to access.
350            loop {
351                curr -= 1;
352                buf[curr].write((n % 10) as u8 + b'0');
353                n /= 10;
354
355                if n == 0 {
356                    break;
357                }
358            }
359            curr
360        }
361
362        #[cfg(feature = "optimize_for_size")]
363        fn ${concat($fmt_fn, _small)}(n: $T, is_nonnegative: bool, f: &mut fmt::Formatter<'_>) -> fmt::Result {
364            const MAX_DEC_N: usize = $T::MAX.ilog(10) as usize + 1;
365            let mut buf = [MaybeUninit::<u8>::uninit(); MAX_DEC_N];
366
367            let offset = ${concat($fmt_fn, _in_buf_small)}(n, &mut buf);
368            // SAFETY: Starting from `offset`, all elements of the slice have been set.
369            let buf_slice = unsafe { slice_buffer_to_str(&buf, offset) };
370            f.pad_integral(is_nonnegative, "", buf_slice)
371        }
372    };
373}
374
375macro_rules! impl_Exp {
376    ($($Signed:ident, $Unsigned:ident),* ; as $T:ident into $fmt_fn:ident) => {
377        fn $fmt_fn(
378            mut n: $T,
379            is_nonnegative: bool,
380            upper: bool,
381            f: &mut fmt::Formatter<'_>
382        ) -> fmt::Result {
383            let (mut n, mut exponent, trailing_zeros, added_precision) = {
384                let mut exponent = 0;
385                // count and remove trailing decimal zeroes
386                while n % 10 == 0 && n >= 10 {
387                    n /= 10;
388                    exponent += 1;
389                }
390                let (added_precision, subtracted_precision) = match f.precision() {
391                    Some(fmt_prec) => {
392                        // number of decimal digits minus 1
393                        let mut tmp = n;
394                        let mut prec = 0;
395                        while tmp >= 10 {
396                            tmp /= 10;
397                            prec += 1;
398                        }
399                        (fmt_prec.saturating_sub(prec), prec.saturating_sub(fmt_prec))
400                    }
401                    None => (0, 0)
402                };
403                for _ in 1..subtracted_precision {
404                    n /= 10;
405                    exponent += 1;
406                }
407                if subtracted_precision != 0 {
408                    let rem = n % 10;
409                    n /= 10;
410                    exponent += 1;
411                    // round up last digit, round to even on a tie
412                    if rem > 5 || (rem == 5 && (n % 2 != 0 || subtracted_precision > 1 )) {
413                        n += 1;
414                        // if the digit is rounded to the next power
415                        // instead adjust the exponent
416                        if n.ilog10() > (n - 1).ilog10() {
417                            n /= 10;
418                            exponent += 1;
419                        }
420                    }
421                }
422                (n, exponent, exponent, added_precision)
423            };
424
425            // Since `curr` always decreases by the number of digits copied, this means
426            // that `curr >= 0`.
427            let mut buf = [MaybeUninit::<u8>::uninit(); 40];
428            let mut curr = buf.len(); //index for buf
429            let buf_ptr = MaybeUninit::slice_as_mut_ptr(&mut buf);
430            let lut_ptr = DEC_DIGITS_LUT.as_ptr();
431
432            // decode 2 chars at a time
433            while n >= 100 {
434                let d1 = ((n % 100) as usize) << 1;
435                curr -= 2;
436                // SAFETY: `d1 <= 198`, so we can copy from `lut_ptr[d1..d1 + 2]` since
437                // `DEC_DIGITS_LUT` has a length of 200.
438                unsafe {
439                    ptr::copy_nonoverlapping(lut_ptr.add(d1), buf_ptr.add(curr), 2);
440                }
441                n /= 100;
442                exponent += 2;
443            }
444            // n is <= 99, so at most 2 chars long
445            let mut n = n as isize; // possibly reduce 64bit math
446            // decode second-to-last character
447            if n >= 10 {
448                curr -= 1;
449                // SAFETY: Safe since `40 > curr >= 0` (see comment)
450                unsafe {
451                    *buf_ptr.add(curr) = (n as u8 % 10_u8) + b'0';
452                }
453                n /= 10;
454                exponent += 1;
455            }
456            // add decimal point iff >1 mantissa digit will be printed
457            if exponent != trailing_zeros || added_precision != 0 {
458                curr -= 1;
459                // SAFETY: Safe since `40 > curr >= 0`
460                unsafe {
461                    *buf_ptr.add(curr) = b'.';
462                }
463            }
464
465            // SAFETY: Safe since `40 > curr >= 0`
466            let buf_slice = unsafe {
467                // decode last character
468                curr -= 1;
469                *buf_ptr.add(curr) = (n as u8) + b'0';
470
471                let len = buf.len() - curr as usize;
472                slice::from_raw_parts(buf_ptr.add(curr), len)
473            };
474
475            // stores 'e' (or 'E') and the up to 2-digit exponent
476            let mut exp_buf = [MaybeUninit::<u8>::uninit(); 3];
477            let exp_ptr = MaybeUninit::slice_as_mut_ptr(&mut exp_buf);
478            // SAFETY: In either case, `exp_buf` is written within bounds and `exp_ptr[..len]`
479            // is contained within `exp_buf` since `len <= 3`.
480            let exp_slice = unsafe {
481                *exp_ptr.add(0) = if upper { b'E' } else { b'e' };
482                let len = if exponent < 10 {
483                    *exp_ptr.add(1) = (exponent as u8) + b'0';
484                    2
485                } else {
486                    let off = exponent << 1;
487                    ptr::copy_nonoverlapping(lut_ptr.add(off), exp_ptr.add(1), 2);
488                    3
489                };
490                slice::from_raw_parts(exp_ptr, len)
491            };
492
493            let parts = &[
494                numfmt::Part::Copy(buf_slice),
495                numfmt::Part::Zero(added_precision),
496                numfmt::Part::Copy(exp_slice),
497            ];
498            let sign = if !is_nonnegative {
499                "-"
500            } else if f.sign_plus() {
501                "+"
502            } else {
503                ""
504            };
505            let formatted = numfmt::Formatted { sign, parts };
506            // SAFETY: `buf_slice` and `exp_slice` contain only ASCII characters.
507            unsafe { f.pad_formatted_parts(&formatted) }
508        }
509
510        $(
511            #[stable(feature = "integer_exp_format", since = "1.42.0")]
512            impl fmt::LowerExp for $Signed {
513                fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
514                    let is_nonnegative = *self >= 0;
515                    let n = if is_nonnegative {
516                        *self as $T
517                    } else {
518                        self.unsigned_abs() as $T
519                    };
520                    $fmt_fn(n, is_nonnegative, false, f)
521                }
522            }
523            #[stable(feature = "integer_exp_format", since = "1.42.0")]
524            impl fmt::LowerExp for $Unsigned {
525                fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
526                    $fmt_fn(*self as $T, true, false, f)
527                }
528            })*
529
530        $(
531            #[stable(feature = "integer_exp_format", since = "1.42.0")]
532            impl fmt::UpperExp for $Signed {
533                fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
534                    let is_nonnegative = *self >= 0;
535                    let n = if is_nonnegative {
536                        *self as $T
537                    } else {
538                        self.unsigned_abs() as $T
539                    };
540                    $fmt_fn(n, is_nonnegative, true, f)
541                }
542            }
543            #[stable(feature = "integer_exp_format", since = "1.42.0")]
544            impl fmt::UpperExp for $Unsigned {
545                fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
546                    $fmt_fn(*self as $T, true, true, f)
547                }
548            })*
549    };
550}
551
552impl_Debug! {
553    i8 i16 i32 i64 i128 isize
554    u8 u16 u32 u64 u128 usize
555}
556
557// Include wasm32 in here since it doesn't reflect the native pointer size, and
558// often cares strongly about getting a smaller code size.
559#[cfg(any(target_pointer_width = "64", target_arch = "wasm32"))]
560mod imp {
561    use super::*;
562    impl_Display!(i8, u8, i16, u16, i32, u32, i64, u64, isize, usize; as u64 into display_u64);
563    impl_Exp!(i8, u8, i16, u16, i32, u32, i64, u64, isize, usize; as u64 into exp_u64);
564}
565
566#[cfg(not(any(target_pointer_width = "64", target_arch = "wasm32")))]
567mod imp {
568    use super::*;
569    impl_Display!(i8, u8, i16, u16, i32, u32, isize, usize; as u32 into display_u32);
570    impl_Display!(i64, u64; as u64 into display_u64);
571
572    impl_Exp!(i8, u8, i16, u16, i32, u32, isize, usize; as u32 into exp_u32);
573    impl_Exp!(i64, u64; as u64 into exp_u64);
574}
575impl_Exp!(i128, u128; as u128 into exp_u128);
576
577const U128_MAX_DEC_N: usize = u128::MAX.ilog10() as usize + 1;
578
579#[stable(feature = "rust1", since = "1.0.0")]
580impl fmt::Display for u128 {
581    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
582        let mut buf = [MaybeUninit::<u8>::uninit(); U128_MAX_DEC_N];
583
584        // SAFETY: `buf` is always big enough to contain all the digits.
585        unsafe { f.pad_integral(true, "", self._fmt(&mut buf)) }
586    }
587}
588
589#[stable(feature = "rust1", since = "1.0.0")]
590impl fmt::Display for i128 {
591    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
592        // This is not a typo, we use the maximum number of digits of `u128`, hence why we use
593        // `U128_MAX_DEC_N`.
594        let mut buf = [MaybeUninit::<u8>::uninit(); U128_MAX_DEC_N];
595
596        let is_nonnegative = *self >= 0;
597        // SAFETY: `buf` is always big enough to contain all the digits.
598        unsafe { f.pad_integral(is_nonnegative, "", self.unsigned_abs()._fmt(&mut buf)) }
599    }
600}
601
602impl u128 {
603    /// Format optimized for u128. Computation of 128 bits is limited by processing
604    /// in batches of 16 decimals at a time.
605    #[doc(hidden)]
606    #[unstable(
607        feature = "fmt_internals",
608        reason = "specialized method meant to only be used by `SpecToString` implementation",
609        issue = "none"
610    )]
611    pub unsafe fn _fmt<'a>(self, buf: &'a mut [MaybeUninit<u8>]) -> &'a str {
612        // SAFETY: `buf` will always be big enough to contain all digits.
613        let offset = unsafe { self._fmt_inner(buf) };
614        // SAFETY: Starting from `offset`, all elements of the slice have been set.
615        unsafe { slice_buffer_to_str(buf, offset) }
616    }
617
618    unsafe fn _fmt_inner(self, buf: &mut [MaybeUninit<u8>]) -> usize {
619        // Optimize common-case zero, which would also need special treatment due to
620        // its "leading" zero.
621        if self == 0 {
622            let offset = buf.len() - 1;
623            buf[offset].write(b'0');
624            return offset;
625        }
626        // Take the 16 least-significant decimals.
627        let (quot_1e16, mod_1e16) = div_rem_1e16(self);
628        let (mut remain, mut offset) = if quot_1e16 == 0 {
629            (mod_1e16, U128_MAX_DEC_N)
630        } else {
631            // Write digits at buf[23..39].
632            enc_16lsd::<{ U128_MAX_DEC_N - 16 }>(buf, mod_1e16);
633
634            // Take another 16 decimals.
635            let (quot2, mod2) = div_rem_1e16(quot_1e16);
636            if quot2 == 0 {
637                (mod2, U128_MAX_DEC_N - 16)
638            } else {
639                // Write digits at buf[7..23].
640                enc_16lsd::<{ U128_MAX_DEC_N - 32 }>(buf, mod2);
641                // Quot2 has at most 7 decimals remaining after two 1e16 divisions.
642                (quot2 as u64, U128_MAX_DEC_N - 32)
643            }
644        };
645
646        // Format per four digits from the lookup table.
647        while remain > 999 {
648            // SAFETY: All of the decimals fit in buf due to U128_MAX_DEC_N
649            // and the while condition ensures at least 4 more decimals.
650            unsafe { core::hint::assert_unchecked(offset >= 4) }
651            // SAFETY: The offset counts down from its initial buf.len()
652            // without underflow due to the previous precondition.
653            unsafe { core::hint::assert_unchecked(offset <= buf.len()) }
654            offset -= 4;
655
656            // pull two pairs
657            let quad = remain % 1_00_00;
658            remain /= 1_00_00;
659            let pair1 = (quad / 100) as usize;
660            let pair2 = (quad % 100) as usize;
661            buf[offset + 0].write(DEC_DIGITS_LUT[pair1 * 2 + 0]);
662            buf[offset + 1].write(DEC_DIGITS_LUT[pair1 * 2 + 1]);
663            buf[offset + 2].write(DEC_DIGITS_LUT[pair2 * 2 + 0]);
664            buf[offset + 3].write(DEC_DIGITS_LUT[pair2 * 2 + 1]);
665        }
666
667        // Format per two digits from the lookup table.
668        if remain > 9 {
669            // SAFETY: All of the decimals fit in buf due to U128_MAX_DEC_N
670            // and the if condition ensures at least 2 more decimals.
671            unsafe { core::hint::assert_unchecked(offset >= 2) }
672            // SAFETY: The offset counts down from its initial buf.len()
673            // without underflow due to the previous precondition.
674            unsafe { core::hint::assert_unchecked(offset <= buf.len()) }
675            offset -= 2;
676
677            let pair = (remain % 100) as usize;
678            remain /= 100;
679            buf[offset + 0].write(DEC_DIGITS_LUT[pair * 2 + 0]);
680            buf[offset + 1].write(DEC_DIGITS_LUT[pair * 2 + 1]);
681        }
682
683        // Format the last remaining digit, if any.
684        if remain != 0 {
685            // SAFETY: All of the decimals fit in buf due to U128_MAX_DEC_N
686            // and the if condition ensures (at least) 1 more decimals.
687            unsafe { core::hint::assert_unchecked(offset >= 1) }
688            // SAFETY: The offset counts down from its initial buf.len()
689            // without underflow due to the previous precondition.
690            unsafe { core::hint::assert_unchecked(offset <= buf.len()) }
691            offset -= 1;
692
693            // Either the compiler sees that remain < 10, or it prevents
694            // a boundary check up next.
695            let last = (remain & 15) as usize;
696            buf[offset].write(DEC_DIGITS_LUT[last * 2 + 1]);
697            // not used: remain = 0;
698        }
699        offset
700    }
701
702    /// Allows users to write an integer (in signed decimal format) into a variable `buf` of
703    /// type [`NumBuffer`] that is passed by the caller by mutable reference.
704    ///
705    /// # Examples
706    ///
707    /// ```
708    /// #![feature(int_format_into)]
709    /// use core::fmt::NumBuffer;
710    ///
711    /// let n = 0u128;
712    /// let mut buf = NumBuffer::new();
713    /// assert_eq!(n.format_into(&mut buf), "0");
714    ///
715    /// let n1 = 32u128;
716    /// let mut buf1 = NumBuffer::new();
717    /// assert_eq!(n1.format_into(&mut buf1), "32");
718    ///
719    /// let n2 = u128::MAX;
720    /// let mut buf2 = NumBuffer::new();
721    /// assert_eq!(n2.format_into(&mut buf2), u128::MAX.to_string());
722    /// ```
723    #[unstable(feature = "int_format_into", issue = "138215")]
724    pub fn format_into(self, buf: &mut NumBuffer<Self>) -> &str {
725        let diff = buf.capacity() - U128_MAX_DEC_N;
726        // FIXME: Once const generics are better, use `NumberBufferTrait::BUF_SIZE` as generic const
727        // for `fmt_u128_inner`.
728        //
729        // In the meantime, we have to use a slice starting at index 1 and add 1 to the returned
730        // offset to ensure the number is correctly generated at the end of the buffer.
731        // SAFETY: `diff` will always be between 0 and its initial value.
732        unsafe { self._fmt(buf.buf.get_unchecked_mut(diff..)) }
733    }
734}
735
736impl i128 {
737    /// Allows users to write an integer (in signed decimal format) into a variable `buf` of
738    /// type [`NumBuffer`] that is passed by the caller by mutable reference.
739    ///
740    /// # Examples
741    ///
742    /// ```
743    /// #![feature(int_format_into)]
744    /// use core::fmt::NumBuffer;
745    ///
746    /// let n = 0i128;
747    /// let mut buf = NumBuffer::new();
748    /// assert_eq!(n.format_into(&mut buf), "0");
749    ///
750    /// let n1 = i128::MIN;
751    /// assert_eq!(n1.format_into(&mut buf), i128::MIN.to_string());
752    ///
753    /// let n2 = i128::MAX;
754    /// assert_eq!(n2.format_into(&mut buf), i128::MAX.to_string());
755    /// ```
756    #[unstable(feature = "int_format_into", issue = "138215")]
757    pub fn format_into(self, buf: &mut NumBuffer<Self>) -> &str {
758        let diff = buf.capacity() - U128_MAX_DEC_N;
759        // FIXME: Once const generics are better, use `NumberBufferTrait::BUF_SIZE` as generic const
760        // for `fmt_u128_inner`.
761        //
762        // In the meantime, we have to use a slice starting at index 1 and add 1 to the returned
763        // offset to ensure the number is correctly generated at the end of the buffer.
764        let mut offset =
765            // SAFETY: `buf` will always be big enough to contain all digits.
766            unsafe { self.unsigned_abs()._fmt_inner(buf.buf.get_unchecked_mut(diff..)) };
767        // We put back the offset at the right position.
768        offset += diff;
769        // Only difference between signed and unsigned are these 4 lines.
770        if self < 0 {
771            offset -= 1;
772            // SAFETY: `buf` will always be big enough to contain all digits plus the minus sign.
773            unsafe {
774                buf.buf.get_unchecked_mut(offset).write(b'-');
775            }
776        }
777        // SAFETY: Starting from `offset`, all elements of the slice have been set.
778        unsafe { slice_buffer_to_str(&buf.buf, offset) }
779    }
780}
781
782/// Encodes the 16 least-significant decimals of n into `buf[OFFSET .. OFFSET +
783/// 16 ]`.
784fn enc_16lsd<const OFFSET: usize>(buf: &mut [MaybeUninit<u8>], n: u64) {
785    // Consume the least-significant decimals from a working copy.
786    let mut remain = n;
787
788    // Format per four digits from the lookup table.
789    for quad_index in (0..4).rev() {
790        // pull two pairs
791        let quad = remain % 1_00_00;
792        remain /= 1_00_00;
793        let pair1 = (quad / 100) as usize;
794        let pair2 = (quad % 100) as usize;
795        buf[quad_index * 4 + OFFSET + 0].write(DEC_DIGITS_LUT[pair1 * 2 + 0]);
796        buf[quad_index * 4 + OFFSET + 1].write(DEC_DIGITS_LUT[pair1 * 2 + 1]);
797        buf[quad_index * 4 + OFFSET + 2].write(DEC_DIGITS_LUT[pair2 * 2 + 0]);
798        buf[quad_index * 4 + OFFSET + 3].write(DEC_DIGITS_LUT[pair2 * 2 + 1]);
799    }
800}
801
802/// Euclidean division plus remainder with constant 1E16 basically consumes 16
803/// decimals from n.
804///
805/// The integer division algorithm is based on the following paper:
806///
807///   T. Granlund and P. Montgomery, “Division by Invariant Integers Using Multiplication”
808///   in Proc. of the SIGPLAN94 Conference on Programming Language Design and
809///   Implementation, 1994, pp. 61–72
810///
811#[inline]
812fn div_rem_1e16(n: u128) -> (u128, u64) {
813    const D: u128 = 1_0000_0000_0000_0000;
814    // The check inlines well with the caller flow.
815    if n < D {
816        return (0, n as u64);
817    }
818
819    // These constant values are computed with the CHOOSE_MULTIPLIER procedure
820    // from the Granlund & Montgomery paper, using N=128, prec=128 and d=1E16.
821    const M_HIGH: u128 = 76624777043294442917917351357515459181;
822    const SH_POST: u8 = 51;
823
824    let quot = n.widening_mul(M_HIGH).1 >> SH_POST;
825    let rem = n - quot * D;
826    (quot, rem as u64)
827}