Skip to main content

core/fmt/
num.rs

1//! Integer and floating-point number formatting
2
3use crate::fmt::NumBuffer;
4use crate::mem::MaybeUninit;
5use crate::num::imp::fmt as numfmt;
6use crate::{fmt, 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// The string of all two-digit numbers in range 00..99 is used as a lookup table.
100static DECIMAL_PAIRS: &[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::MIN < 0, "need signed");
127            assert!($Unsigned::MIN == 0, "need unsigned");
128            assert!($Signed::BITS == $Unsigned::BITS, "need counterparts");
129            assert!($Signed::BITS <= $T::BITS, "need lossless conversion");
130            assert!($Unsigned::BITS <= $T::BITS, "need lossless conversion");
131        };
132
133        #[stable(feature = "rust1", since = "1.0.0")]
134        impl fmt::Display for $Unsigned {
135            fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
136                #[cfg(not(feature = "optimize_for_size"))]
137                {
138                    const MAX_DEC_N: usize = $Unsigned::MAX.ilog10() as usize + 1;
139                    // Buffer decimals for self with right alignment.
140                    let mut buf = [MaybeUninit::<u8>::uninit(); MAX_DEC_N];
141
142                    // SAFETY: `buf` is always big enough to contain all the digits.
143                    unsafe { f.pad_integral(true, "", self._fmt(&mut buf)) }
144                }
145                #[cfg(feature = "optimize_for_size")]
146                {
147                    // Lossless conversion (with as) is asserted at the top of
148                    // this macro.
149                    ${concat($fmt_fn, _small)}(*self as $T, true, f)
150                }
151            }
152        }
153
154        #[stable(feature = "rust1", since = "1.0.0")]
155        impl fmt::Display for $Signed {
156            fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
157                #[cfg(not(feature = "optimize_for_size"))]
158                {
159                    const MAX_DEC_N: usize = $Unsigned::MAX.ilog10() as usize + 1;
160                    // Buffer decimals for self with right alignment.
161                    let mut buf = [MaybeUninit::<u8>::uninit(); MAX_DEC_N];
162
163                    // SAFETY: `buf` is always big enough to contain all the digits.
164                    unsafe { f.pad_integral(*self >= 0, "", self.unsigned_abs()._fmt(&mut buf)) }
165                }
166                #[cfg(feature = "optimize_for_size")]
167                {
168                    // Lossless conversion (with as) is asserted at the top of
169                    // this macro.
170                    return ${concat($fmt_fn, _small)}(self.unsigned_abs() as $T, *self >= 0, f);
171                }
172            }
173        }
174
175        #[cfg(not(feature = "optimize_for_size"))]
176        impl $Unsigned {
177            #[doc(hidden)]
178            #[unstable(
179                feature = "fmt_internals",
180                reason = "specialized method meant to only be used by `SpecToString` implementation",
181                issue = "none"
182            )]
183            pub unsafe fn _fmt<'a>(self, buf: &'a mut [MaybeUninit::<u8>]) -> &'a str {
184                // SAFETY: `buf` will always be big enough to contain all digits.
185                let offset = unsafe { self._fmt_inner(buf) };
186                // SAFETY: Starting from `offset`, all elements of the slice have been set.
187                unsafe { slice_buffer_to_str(buf, offset) }
188            }
189
190            unsafe fn _fmt_inner(self, buf: &mut [MaybeUninit::<u8>]) -> usize {
191                // Count the number of bytes in buf that are not initialized.
192                let mut offset = buf.len();
193                // Consume the least-significant decimals from a working copy.
194                let mut remain = self;
195
196                // Format per four digits from the lookup table.
197                // Four digits need a 16-bit $Unsigned or wider.
198                while size_of::<Self>() > 1 && remain > 999.try_into().expect("branch is not hit for types that cannot fit 999 (u8)") {
199                    // SAFETY: All of the decimals fit in buf due to MAX_DEC_N
200                    // and the while condition ensures at least 4 more decimals.
201                    unsafe { core::hint::assert_unchecked(offset >= 4) }
202                    // SAFETY: The offset counts down from its initial buf.len()
203                    // without underflow due to the previous precondition.
204                    unsafe { core::hint::assert_unchecked(offset <= buf.len()) }
205                    offset -= 4;
206
207                    // pull two pairs
208                    let scale: Self = 1_00_00.try_into().expect("branch is not hit for types that cannot fit 1E4 (u8)");
209                    let quad = remain % scale;
210                    remain /= scale;
211                    let pair1 = (quad / 100) as usize;
212                    let pair2 = (quad % 100) as usize;
213                    buf[offset + 0].write(DECIMAL_PAIRS[pair1 * 2 + 0]);
214                    buf[offset + 1].write(DECIMAL_PAIRS[pair1 * 2 + 1]);
215                    buf[offset + 2].write(DECIMAL_PAIRS[pair2 * 2 + 0]);
216                    buf[offset + 3].write(DECIMAL_PAIRS[pair2 * 2 + 1]);
217                }
218
219                // Format per two digits from the lookup table.
220                if remain > 9 {
221                    // SAFETY: All of the decimals fit in buf due to MAX_DEC_N
222                    // and the if condition ensures at least 2 more decimals.
223                    unsafe { core::hint::assert_unchecked(offset >= 2) }
224                    // SAFETY: The offset counts down from its initial buf.len()
225                    // without underflow due to the previous precondition.
226                    unsafe { core::hint::assert_unchecked(offset <= buf.len()) }
227                    offset -= 2;
228
229                    let pair = (remain % 100) as usize;
230                    remain /= 100;
231                    buf[offset + 0].write(DECIMAL_PAIRS[pair * 2 + 0]);
232                    buf[offset + 1].write(DECIMAL_PAIRS[pair * 2 + 1]);
233                }
234
235                // Format the last remaining digit, if any.
236                if remain != 0 || self == 0 {
237                    // SAFETY: All of the decimals fit in buf due to MAX_DEC_N
238                    // and the if condition ensures (at least) 1 more decimals.
239                    unsafe { core::hint::assert_unchecked(offset >= 1) }
240                    // SAFETY: The offset counts down from its initial buf.len()
241                    // without underflow due to the previous precondition.
242                    unsafe { core::hint::assert_unchecked(offset <= buf.len()) }
243                    offset -= 1;
244
245                    // Either the compiler sees that remain < 10, or it prevents
246                    // a boundary check up next.
247                    let last = (remain & 15) as usize;
248                    buf[offset].write(DECIMAL_PAIRS[last * 2 + 1]);
249                    // not used: remain = 0;
250                }
251
252                offset
253            }
254        }
255
256        impl $Signed {
257            /// Allows users to write an integer (in signed decimal format) into a variable `buf` of
258            /// type [`NumBuffer`] that is passed by the caller by mutable reference.
259            ///
260            /// # Examples
261            ///
262            /// ```
263            /// use core::fmt::NumBuffer;
264            ///
265            #[doc = concat!("let n = 0", stringify!($Signed), ";")]
266            /// let mut buf = NumBuffer::new();
267            /// assert_eq!(n.format_into(&mut buf), "0");
268            ///
269            #[doc = concat!("let n1 = 32", stringify!($Signed), ";")]
270            /// assert_eq!(n1.format_into(&mut buf), "32");
271            ///
272            #[doc = concat!("let n2 = ", stringify!($Signed::MAX), ";")]
273            #[doc = concat!("assert_eq!(n2.format_into(&mut buf), ", stringify!($Signed::MAX), ".to_string());")]
274            /// ```
275            #[stable(feature = "int_format_into", since = "1.98.0")]
276            pub fn format_into(self, buf: &mut NumBuffer<Self>) -> &str {
277                let mut offset;
278
279                #[cfg(not(feature = "optimize_for_size"))]
280                // SAFETY: `buf` will always be big enough to contain all digits.
281                unsafe {
282                    offset = self.unsigned_abs()._fmt_inner(&mut buf.buf);
283                }
284                #[cfg(feature = "optimize_for_size")]
285                {
286                    // Lossless conversion (with as) is asserted at the top of
287                    // this macro.
288                    offset = ${concat($fmt_fn, _in_buf_small)}(self.unsigned_abs() as $T, &mut buf.buf);
289                }
290                // Only difference between signed and unsigned are these 4 lines.
291                if self < 0 {
292                    offset -= 1;
293                    buf.buf[offset].write(b'-');
294                }
295                // SAFETY: Starting from `offset`, all elements of the slice have been set.
296                unsafe { slice_buffer_to_str(&buf.buf, offset) }
297            }
298        }
299
300        impl $Unsigned {
301            /// Allows users to write an integer (in unsigned decimal format) into a variable `buf`
302            /// of type [`NumBuffer`] that is passed by the caller by mutable reference.
303            ///
304            /// # Examples
305            ///
306            /// ```
307            /// use core::fmt::NumBuffer;
308            ///
309            #[doc = concat!("let n = 0", stringify!($Unsigned), ";")]
310            /// let mut buf = NumBuffer::new();
311            /// assert_eq!(n.format_into(&mut buf), "0");
312            ///
313            #[doc = concat!("let n1 = 32", stringify!($Unsigned), ";")]
314            /// assert_eq!(n1.format_into(&mut buf), "32");
315            ///
316            #[doc = concat!("let n2 = ", stringify!($Unsigned::MAX), ";")]
317            #[doc = concat!("assert_eq!(n2.format_into(&mut buf), ", stringify!($Unsigned::MAX), ".to_string());")]
318            /// ```
319            #[stable(feature = "int_format_into", since = "1.98.0")]
320            pub fn format_into(self, buf: &mut NumBuffer<Self>) -> &str {
321                let offset;
322
323                #[cfg(not(feature = "optimize_for_size"))]
324                // SAFETY: `buf` will always be big enough to contain all digits.
325                unsafe {
326                    offset = self._fmt_inner(&mut buf.buf);
327                }
328                #[cfg(feature = "optimize_for_size")]
329                {
330                    // Lossless conversion (with as) is asserted at the top of
331                    // this macro.
332                    offset = ${concat($fmt_fn, _in_buf_small)}(self as $T, &mut buf.buf);
333                }
334                // SAFETY: Starting from `offset`, all elements of the slice have been set.
335                unsafe { slice_buffer_to_str(&buf.buf, offset) }
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.ilog10() 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        const _: () = assert!($T::MIN == 0, "need unsigned");
378
379        fn $fmt_fn(
380            f: &mut fmt::Formatter<'_>,
381            n: $T,
382            is_nonnegative: bool,
383            letter_e: u8
384        ) -> fmt::Result {
385            debug_assert!(letter_e.is_ascii_alphabetic(), "single-byte character");
386
387            // Print the integer as a coefficient in range (-10, 10).
388            let mut exp = n.checked_ilog10().unwrap_or(0) as usize;
389            debug_assert!(n / (10 as $T).pow(exp as u32) < 10);
390
391            // Precisison is counted as the number of digits in the fraction.
392            let mut coef_prec = exp;
393            // Keep the digits as an integer (paired with its coef_prec count).
394            let mut coef = n;
395
396            // A Formatter may set the precision to a fixed number of decimals.
397            let more_prec = match f.precision() {
398                None => {
399                    // Omit any and all trailing zeroes.
400                    while coef_prec != 0 && coef % 10 == 0 {
401                        coef /= 10;
402                        coef_prec -= 1;
403                    }
404                    0
405                },
406
407                Some(fmt_prec) if fmt_prec >= coef_prec => {
408                    // Count the number of additional zeroes needed.
409                    fmt_prec - coef_prec
410                },
411
412                Some(fmt_prec) => {
413                    // Count the number of digits to drop.
414                    let less_prec = coef_prec - fmt_prec;
415                    assert!(less_prec > 0);
416                    // Scale down the coefficient/precision pair. For example,
417                    // coef 123456 gets coef_prec 5 (to make 1.23456). To format
418                    // the number with 2 decimals, i.e., fmt_prec 2, coef should
419                    // be scaled by 10⁵⁻²=1000 to get coef 123 with coef_prec 2.
420
421                    // SAFETY: Any precision less than coef_prec will cause a
422                    // power of ten below the coef value.
423                    let scale = unsafe {
424                        (10 as $T).checked_pow(less_prec as u32).unwrap_unchecked()
425                    };
426                    let floor = coef / scale;
427                    // Round half to even conform documentation.
428                    let over = coef % scale;
429                    let half = scale / 2;
430                    let round_up = if over < half {
431                        0
432                    } else if over > half {
433                        1
434                    } else {
435                        floor & 1 // round odd up to even
436                    };
437                    // Adding one to a scale down of at least 10 won't overflow.
438                    coef = floor + round_up;
439                    coef_prec = fmt_prec;
440
441                    // The round_up may have caused the coefficient to reach 10
442                    // (which is not permitted). For example, anything in range
443                    // [9.95, 10) becomes 10.0 when adjusted to precision 1.
444                    if round_up != 0 && coef.checked_ilog10().unwrap_or(0) as usize > coef_prec {
445                        debug_assert_eq!(coef, (10 as $T).pow(coef_prec as u32 + 1));
446                        coef /= 10; // drop one trailing zero
447                        exp += 1;   // one power of ten higher
448                    }
449                    0
450                },
451            };
452
453            // Allocate a text buffer with lazy initialization.
454            const MAX_DEC_N: usize = $T::MAX.ilog10() as usize + 1;
455            const MAX_COEF_LEN: usize = MAX_DEC_N + ".".len();
456            const MAX_TEXT_LEN: usize = MAX_COEF_LEN + "e99".len();
457            let mut buf = [MaybeUninit::<u8>::uninit(); MAX_TEXT_LEN];
458
459            // Encode the coefficient in buf[..coef_len].
460            let (lead_dec, coef_len) = if coef_prec == 0 && more_prec == 0 {
461                (coef, 1_usize) // single digit; no fraction
462            } else {
463                buf[1].write(b'.');
464                let fraction_range = 2..(2 + coef_prec);
465
466                // Consume the least-significant decimals from a working copy.
467                let mut remain = coef;
468                #[cfg(feature = "optimize_for_size")] {
469                    for i in fraction_range.clone().rev() {
470                        let digit = (remain % 10) as usize;
471                        remain /= 10;
472                        buf[i].write(b'0' + digit as u8);
473                    }
474                }
475                #[cfg(not(feature = "optimize_for_size"))] {
476                    // Write digits per two at a time with a lookup table.
477                    for i in fraction_range.clone().skip(1).rev().step_by(2) {
478                        let pair = (remain % 100) as usize;
479                        remain /= 100;
480                        buf[i - 1].write(DECIMAL_PAIRS[pair * 2 + 0]);
481                        buf[i - 0].write(DECIMAL_PAIRS[pair * 2 + 1]);
482                    }
483                    // An odd number of digits leave one digit remaining.
484                    if coef_prec & 1 != 0 {
485                        let digit = (remain % 10) as usize;
486                        remain /= 10;
487                        buf[fraction_range.start].write(b'0' + digit as u8);
488                    }
489                }
490
491                (remain, fraction_range.end)
492            };
493            debug_assert!(lead_dec < 10);
494            debug_assert!(lead_dec != 0 || coef == 0, "significant digits only");
495            buf[0].write(b'0' + lead_dec as u8);
496
497            // SAFETY: The number of decimals is limited, captured by MAX.
498            unsafe { core::hint::assert_unchecked(coef_len <= MAX_COEF_LEN) }
499            // Encode the scale factor in buf[coef_len..text_len].
500            buf[coef_len].write(letter_e);
501            let text_len: usize = match exp {
502                ..10 => {
503                    buf[coef_len + 1].write(b'0' + exp as u8);
504                    coef_len + 2
505                },
506                10..100 => {
507                    #[cfg(feature = "optimize_for_size")] {
508                        buf[coef_len + 1].write(b'0' + (exp / 10) as u8);
509                        buf[coef_len + 2].write(b'0' + (exp % 10) as u8);
510                    }
511                    #[cfg(not(feature = "optimize_for_size"))] {
512                        buf[coef_len + 1].write(DECIMAL_PAIRS[exp * 2 + 0]);
513                        buf[coef_len + 2].write(DECIMAL_PAIRS[exp * 2 + 1]);
514                    }
515                    coef_len + 3
516                },
517                _ => {
518                    const { assert!($T::MAX.ilog10() < 100) };
519                    // SAFETY: A `u256::MAX` would get exponent 77.
520                    unsafe { core::hint::unreachable_unchecked() }
521                }
522            };
523            // SAFETY: All bytes up until text_len have been set.
524            let text = unsafe { buf[..text_len].assume_init_ref() };
525
526            if more_prec == 0 {
527                // SAFETY: Text is set with ASCII exclusively: either a decimal,
528                // or a LETTER_E, or a dot. ASCII implies valid UTF-8.
529                let as_str = unsafe { str::from_utf8_unchecked(text) };
530                f.pad_integral(is_nonnegative, "", as_str)
531            } else {
532                let parts = &[
533                    numfmt::Part::Copy(&text[..coef_len]),
534                    numfmt::Part::Zero(more_prec),
535                    numfmt::Part::Copy(&text[coef_len..]),
536                ];
537                let sign = if !is_nonnegative {
538                    "-"
539                } else if f.sign_plus() {
540                    "+"
541                } else {
542                    ""
543                };
544                // SAFETY: Text is set with ASCII exclusively: either a decimal,
545                // or a LETTER_E, or a dot. ASCII implies valid UTF-8.
546                unsafe { f.pad_formatted_parts(&numfmt::Formatted { sign, parts }) }
547            }
548        }
549
550        $(
551        const _: () = {
552            assert!($Signed::MIN < 0, "need signed");
553            assert!($Unsigned::MIN == 0, "need unsigned");
554            assert!($Signed::BITS == $Unsigned::BITS, "need counterparts");
555            assert!($Signed::BITS <= $T::BITS, "need lossless conversion");
556            assert!($Unsigned::BITS <= $T::BITS, "need lossless conversion");
557        };
558        #[stable(feature = "integer_exp_format", since = "1.42.0")]
559        impl fmt::LowerExp for $Signed {
560            fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
561                $fmt_fn(f, self.unsigned_abs() as $T, *self >= 0, b'e')
562            }
563        }
564        #[stable(feature = "integer_exp_format", since = "1.42.0")]
565        impl fmt::LowerExp for $Unsigned {
566            fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
567                $fmt_fn(f, *self as $T, true, b'e')
568            }
569        }
570        #[stable(feature = "integer_exp_format", since = "1.42.0")]
571        impl fmt::UpperExp for $Signed {
572            fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
573                $fmt_fn(f, self.unsigned_abs() as $T, *self >= 0, b'E')
574            }
575        }
576        #[stable(feature = "integer_exp_format", since = "1.42.0")]
577        impl fmt::UpperExp for $Unsigned {
578            fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
579                $fmt_fn(f, *self as $T, true, b'E')
580            }
581        }
582        )*
583
584    };
585}
586
587impl_Debug! {
588    i8 i16 i32 i64 i128 isize
589    u8 u16 u32 u64 u128 usize
590}
591
592// Include wasm32 in here since it doesn't reflect the native pointer size, and
593// often cares strongly about getting a smaller code size.
594#[cfg(any(target_pointer_width = "64", target_arch = "wasm32"))]
595#[doc(auto_cfg = false)]
596mod imp {
597    use super::*;
598    impl_Display!(i8, u8, i16, u16, i32, u32, i64, u64, isize, usize; as u64 into display_u64);
599    impl_Exp!(i8, u8, i16, u16, i32, u32, i64, u64, isize, usize; as u64 into exp_u64);
600}
601
602#[cfg(not(any(target_pointer_width = "64", target_arch = "wasm32")))]
603#[doc(auto_cfg = false)]
604mod imp {
605    use super::*;
606    impl_Display!(i8, u8, i16, u16, i32, u32, isize, usize; as u32 into display_u32);
607    impl_Display!(i64, u64; as u64 into display_u64);
608
609    impl_Exp!(i8, u8, i16, u16, i32, u32, isize, usize; as u32 into exp_u32);
610    impl_Exp!(i64, u64; as u64 into exp_u64);
611}
612impl_Exp!(i128, u128; as u128 into exp_u128);
613
614const U128_MAX_DEC_N: usize = u128::MAX.ilog10() as usize + 1;
615
616#[stable(feature = "rust1", since = "1.0.0")]
617impl fmt::Display for u128 {
618    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
619        let mut buf = [MaybeUninit::<u8>::uninit(); U128_MAX_DEC_N];
620
621        // SAFETY: `buf` is always big enough to contain all the digits.
622        unsafe { f.pad_integral(true, "", self._fmt(&mut buf)) }
623    }
624}
625
626#[stable(feature = "rust1", since = "1.0.0")]
627impl fmt::Display for i128 {
628    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
629        // This is not a typo, we use the maximum number of digits of `u128`, hence why we use
630        // `U128_MAX_DEC_N`.
631        let mut buf = [MaybeUninit::<u8>::uninit(); U128_MAX_DEC_N];
632
633        let is_nonnegative = *self >= 0;
634        // SAFETY: `buf` is always big enough to contain all the digits.
635        unsafe { f.pad_integral(is_nonnegative, "", self.unsigned_abs()._fmt(&mut buf)) }
636    }
637}
638
639impl u128 {
640    /// Format optimized for u128. Computation of 128 bits is limited by processing
641    /// in batches of 16 decimals at a time.
642    #[doc(hidden)]
643    #[unstable(
644        feature = "fmt_internals",
645        reason = "specialized method meant to only be used by `SpecToString` implementation",
646        issue = "none"
647    )]
648    pub unsafe fn _fmt<'a>(self, buf: &'a mut [MaybeUninit<u8>]) -> &'a str {
649        // SAFETY: `buf` will always be big enough to contain all digits.
650        let offset = unsafe { self._fmt_inner(buf) };
651        // SAFETY: Starting from `offset`, all elements of the slice have been set.
652        unsafe { slice_buffer_to_str(buf, offset) }
653    }
654
655    unsafe fn _fmt_inner(self, buf: &mut [MaybeUninit<u8>]) -> usize {
656        // Optimize common-case zero, which would also need special treatment due to
657        // its "leading" zero.
658        if self == 0 {
659            let offset = buf.len() - 1;
660            buf[offset].write(b'0');
661            return offset;
662        }
663        // Take the 16 least-significant decimals.
664        let (quot_1e16, mod_1e16) = div_rem_1e16(self);
665        let (mut remain, mut offset) = if quot_1e16 == 0 {
666            (mod_1e16, U128_MAX_DEC_N)
667        } else {
668            // Write digits at buf[23..39].
669            //
670            // SAFETY: `mod_1e16 < 1e16` (remainder), and `U128_MAX_DEC_N - 16 + 16 == buf.len()`.
671            unsafe { enc_16lsd::<{ U128_MAX_DEC_N - 16 }>(buf, mod_1e16) };
672
673            // Take another 16 decimals.
674            let (quot2, mod2) = div_rem_1e16(quot_1e16);
675            if quot2 == 0 {
676                (mod2, U128_MAX_DEC_N - 16)
677            } else {
678                // Write digits at buf[7..23].
679                //
680                // SAFETY: `mod2 < 1e16` (remainder), and `U128_MAX_DEC_N - 32 + 16 <= buf.len()`.
681                unsafe { enc_16lsd::<{ U128_MAX_DEC_N - 32 }>(buf, mod2) };
682
683                // Quot2 has at most 7 decimals remaining after two 1e16 divisions.
684                (quot2 as u64, U128_MAX_DEC_N - 32)
685            }
686        };
687
688        // Format per four digits from the lookup table.
689        while remain > 999 {
690            // SAFETY: All of the decimals fit in buf due to U128_MAX_DEC_N
691            // and the while condition ensures at least 4 more decimals.
692            unsafe { core::hint::assert_unchecked(offset >= 4) }
693            // SAFETY: The offset counts down from its initial buf.len()
694            // without underflow due to the previous precondition.
695            unsafe { core::hint::assert_unchecked(offset <= buf.len()) }
696            offset -= 4;
697
698            let quad = remain % 1_00_00;
699            remain /= 1_00_00;
700
701            // SAFETY: quad is a remainder modulo 10_000. The offset checks
702            // above reserve exactly four bytes in buf.
703            unsafe {
704                write_quad(buf.get_unchecked_mut(offset..offset + 4), quad);
705            }
706        }
707
708        // Format per two digits from the lookup table.
709        if remain > 9 {
710            // SAFETY: All of the decimals fit in buf due to U128_MAX_DEC_N
711            // and the if condition ensures at least 2 more decimals.
712            unsafe { core::hint::assert_unchecked(offset >= 2) }
713            // SAFETY: The offset counts down from its initial buf.len()
714            // without underflow due to the previous precondition.
715            unsafe { core::hint::assert_unchecked(offset <= buf.len()) }
716            offset -= 2;
717
718            let pair = (remain % 100) as usize;
719            remain /= 100;
720            buf[offset + 0].write(DECIMAL_PAIRS[pair * 2 + 0]);
721            buf[offset + 1].write(DECIMAL_PAIRS[pair * 2 + 1]);
722        }
723
724        // Format the last remaining digit, if any.
725        if remain != 0 {
726            // SAFETY: All of the decimals fit in buf due to U128_MAX_DEC_N
727            // and the if condition ensures (at least) 1 more decimals.
728            unsafe { core::hint::assert_unchecked(offset >= 1) }
729            // SAFETY: The offset counts down from its initial buf.len()
730            // without underflow due to the previous precondition.
731            unsafe { core::hint::assert_unchecked(offset <= buf.len()) }
732            offset -= 1;
733
734            // Either the compiler sees that remain < 10, or it prevents
735            // a boundary check up next.
736            let last = (remain & 15) as usize;
737            buf[offset].write(DECIMAL_PAIRS[last * 2 + 1]);
738            // not used: remain = 0;
739        }
740        offset
741    }
742
743    /// Allows users to write an integer (in unsigned decimal format) into a variable `buf` of
744    /// type [`NumBuffer`] that is passed by the caller by mutable reference.
745    ///
746    /// # Examples
747    ///
748    /// ```
749    /// use core::fmt::NumBuffer;
750    ///
751    /// let n = 0u128;
752    /// let mut buf = NumBuffer::new();
753    /// assert_eq!(n.format_into(&mut buf), "0");
754    ///
755    /// let n1 = 32u128;
756    /// let mut buf1 = NumBuffer::new();
757    /// assert_eq!(n1.format_into(&mut buf1), "32");
758    ///
759    /// let n2 = u128::MAX;
760    /// let mut buf2 = NumBuffer::new();
761    /// assert_eq!(n2.format_into(&mut buf2), u128::MAX.to_string());
762    /// ```
763    #[stable(feature = "int_format_into", since = "1.98.0")]
764    pub fn format_into(self, buf: &mut NumBuffer<Self>) -> &str {
765        let diff = buf.buf.len() - U128_MAX_DEC_N;
766        // FIXME: Once const generics are better, use `NumberBufferTrait::BUF_SIZE` as generic const
767        // for `fmt_u128_inner`.
768        //
769        // In the meantime, we have to use a slice starting at index 1 and add 1 to the returned
770        // offset to ensure the number is correctly generated at the end of the buffer.
771        // SAFETY: `diff` will always be between 0 and its initial value.
772        unsafe { self._fmt(buf.buf.get_unchecked_mut(diff..)) }
773    }
774}
775
776impl i128 {
777    /// Allows users to write an integer (in signed decimal format) into a variable `buf` of
778    /// type [`NumBuffer`] that is passed by the caller by mutable reference.
779    ///
780    /// # Examples
781    ///
782    /// ```
783    /// use core::fmt::NumBuffer;
784    ///
785    /// let n = 0i128;
786    /// let mut buf = NumBuffer::new();
787    /// assert_eq!(n.format_into(&mut buf), "0");
788    ///
789    /// let n1 = i128::MIN;
790    /// assert_eq!(n1.format_into(&mut buf), i128::MIN.to_string());
791    ///
792    /// let n2 = i128::MAX;
793    /// assert_eq!(n2.format_into(&mut buf), i128::MAX.to_string());
794    /// ```
795    #[stable(feature = "int_format_into", since = "1.98.0")]
796    pub fn format_into(self, buf: &mut NumBuffer<Self>) -> &str {
797        let diff = buf.buf.len() - U128_MAX_DEC_N;
798        // FIXME: Once const generics are better, use `NumberBufferTrait::BUF_SIZE` as generic const
799        // for `fmt_u128_inner`.
800        //
801        // In the meantime, we have to use a slice starting at index 1 and add 1 to the returned
802        // offset to ensure the number is correctly generated at the end of the buffer.
803        let mut offset =
804            // SAFETY: `buf` will always be big enough to contain all digits.
805            unsafe { self.unsigned_abs()._fmt_inner(buf.buf.get_unchecked_mut(diff..)) };
806        // We put back the offset at the right position.
807        offset += diff;
808        // Only difference between signed and unsigned are these 4 lines.
809        if self < 0 {
810            offset -= 1;
811            // SAFETY: `buf` will always be big enough to contain all digits plus the minus sign.
812            unsafe {
813                buf.buf.get_unchecked_mut(offset).write(b'-');
814            }
815        }
816        // SAFETY: Starting from `offset`, all elements of the slice have been set.
817        unsafe { slice_buffer_to_str(&buf.buf, offset) }
818    }
819}
820
821/// Writes `quad` as exactly four digits (for example: `42` becomes `"0042"`).
822///
823/// # Safety
824///
825/// `quad` must be below 10_000 and `buf` must contain exactly four bytes.
826#[inline(always)]
827unsafe fn write_quad(buf: &mut [MaybeUninit<u8>], quad: u64) {
828    // SAFETY: These are this function's caller-provided invariants.
829    unsafe {
830        core::hint::assert_unchecked(quad < 10_000);
831        core::hint::assert_unchecked(buf.len() == 4);
832    }
833
834    let quad = quad as u32;
835
836    // Note: this is equivalent to `quad / 100`, but contains no division instructions.
837    let high = (quad * const { (1 << 19) / 100 + 1 }) >> 19;
838    let low = quad - high * 100;
839    let high = high as usize;
840    let low = low as usize;
841
842    // SAFETY: `high` and `low` are below 100 because `quad` is below 10_000.
843    unsafe { core::hint::assert_unchecked(high < 100 && low < 100) }
844
845    buf[0..2].write_copy_of_slice(&DECIMAL_PAIRS[high * 2..high * 2 + 2]);
846    buf[2..4].write_copy_of_slice(&DECIMAL_PAIRS[low * 2..low * 2 + 2]);
847}
848
849/// Encodes the 16 least-significant decimals of n into `buf[OFFSET .. OFFSET +
850/// 16 ]`.
851///
852/// # Safety
853///
854/// `n` must be below 1e16, and `buf` must be at least `OFFSET + 16` bytes long.
855unsafe fn enc_16lsd<const OFFSET: usize>(buf: &mut [MaybeUninit<u8>], n: u64) {
856    // SAFETY: Every caller passes a remainder produced by division by 10^16,
857    // and every used `OFFSET` specialization reserves sixteen bytes in `buf`.
858    unsafe {
859        core::hint::assert_unchecked(n < 10_000_000_000_000_000);
860        core::hint::assert_unchecked(OFFSET + 16 <= buf.len());
861    }
862
863    // Peel four digits at a time from right to left (12345678 -> 1234 | 5678).
864    // Since 10_000 is constant, LLVM replaces each division with multiply or shift.
865    let mut remain = n;
866
867    for quad_index in (1..4).rev() {
868        let quad = remain % 1_00_00;
869        remain /= 1_00_00;
870
871        // SAFETY: `OFFSET + quad_index * 4` starts one of the four
872        // non-overlapping four-byte regions proven in bounds above.
873        unsafe {
874            write_quad(
875                buf.get_unchecked_mut(OFFSET + quad_index * 4..OFFSET + (quad_index + 1) * 4),
876                quad,
877            );
878        }
879    }
880
881    // SAFETY: OFFSET starts the first four-byte region proven in bounds above.
882    unsafe {
883        write_quad(buf.get_unchecked_mut(OFFSET..OFFSET + 4), remain);
884    }
885}
886
887/// Euclidean division plus remainder with constant 1E16 basically consumes 16
888/// decimals from n.
889///
890/// The integer division algorithm is based on the following paper:
891///
892///   T. Granlund and P. Montgomery, “Division by Invariant Integers Using Multiplication”
893///   in Proc. of the SIGPLAN94 Conference on Programming Language Design and
894///   Implementation, 1994, pp. 61–72
895///
896#[inline]
897fn div_rem_1e16(n: u128) -> (u128, u64) {
898    const D: u128 = 1_0000_0000_0000_0000;
899    // The check inlines well with the caller flow.
900    if n < D {
901        return (0, n as u64);
902    }
903
904    // These constant values are computed with the CHOOSE_MULTIPLIER procedure
905    // from the Granlund & Montgomery paper, using N=128, prec=128 and d=1E16.
906    const M_HIGH: u128 = 76624777043294442917917351357515459181;
907    const SH_POST: u8 = 51;
908
909    let quot = n.carrying_mul(M_HIGH, 0).1 >> SH_POST;
910    let rem = n - quot * D;
911    (quot, rem as u64)
912}