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