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