1use crate::mem::MaybeUninit;
4use crate::num::fmt as numfmt;
5use crate::ops::{Div, Rem, Sub};
6use crate::{fmt, ptr, slice, str};
7
8#[doc(hidden)]
9trait DisplayInt:
10 PartialEq + PartialOrd + Div<Output = Self> + Rem<Output = Self> + Sub<Output = Self> + Copy
11{
12 fn zero() -> Self;
13 fn from_u8(u: u8) -> Self;
14 fn to_u8(&self) -> u8;
15 #[cfg(not(any(target_pointer_width = "64", target_arch = "wasm32")))]
16 fn to_u32(&self) -> u32;
17 fn to_u64(&self) -> u64;
18 fn to_u128(&self) -> u128;
19}
20
21macro_rules! impl_int {
22 ($($t:ident)*) => (
23 $(impl DisplayInt for $t {
24 fn zero() -> Self { 0 }
25 fn from_u8(u: u8) -> Self { u as Self }
26 fn to_u8(&self) -> u8 { *self as u8 }
27 #[cfg(not(any(target_pointer_width = "64", target_arch = "wasm32")))]
28 fn to_u32(&self) -> u32 { *self as u32 }
29 fn to_u64(&self) -> u64 { *self as u64 }
30 fn to_u128(&self) -> u128 { *self as u128 }
31 })*
32 )
33}
34
35impl_int! {
36 i8 i16 i32 i64 i128 isize
37 u8 u16 u32 u64 u128 usize
38}
39
40#[doc(hidden)]
46unsafe trait GenericRadix: Sized {
47 const BASE: u8;
49
50 const PREFIX: &'static str;
52
53 fn digit(x: u8) -> u8;
55
56 fn fmt_int<T: DisplayInt>(&self, mut x: T, f: &mut fmt::Formatter<'_>) -> fmt::Result {
58 let zero = T::zero();
61 let is_nonnegative = x >= zero;
62 let mut buf = [MaybeUninit::<u8>::uninit(); 128];
63 let mut curr = buf.len();
64 let base = T::from_u8(Self::BASE);
65 if is_nonnegative {
66 loop {
69 let n = x % base; x = x / base; curr -= 1;
72 buf[curr].write(Self::digit(n.to_u8())); if x == zero {
74 break;
76 };
77 }
78 } else {
79 loop {
81 let n = zero - (x % base); x = x / base; curr -= 1;
84 buf[curr].write(Self::digit(n.to_u8())); if x == zero {
86 break;
88 };
89 }
90 }
91 let buf = unsafe { buf.get_unchecked(curr..) };
95 let buf = unsafe {
98 str::from_utf8_unchecked(slice::from_raw_parts(
99 MaybeUninit::slice_as_ptr(buf),
100 buf.len(),
101 ))
102 };
103 f.pad_integral(is_nonnegative, Self::PREFIX, buf)
104 }
105}
106
107#[derive(Clone, PartialEq)]
109struct Binary;
110
111#[derive(Clone, PartialEq)]
113struct Octal;
114
115#[derive(Clone, PartialEq)]
117struct LowerHex;
118
119#[derive(Clone, PartialEq)]
121struct UpperHex;
122
123macro_rules! radix {
124 ($T:ident, $base:expr, $prefix:expr, $($x:pat => $conv:expr),+) => {
125 unsafe impl GenericRadix for $T {
126 const BASE: u8 = $base;
127 const PREFIX: &'static str = $prefix;
128 fn digit(x: u8) -> u8 {
129 match x {
130 $($x => $conv,)+
131 x => panic!("number not in the range 0..={}: {}", Self::BASE - 1, x),
132 }
133 }
134 }
135 }
136}
137
138radix! { Binary, 2, "0b", x @ 0 ..= 1 => b'0' + x }
139radix! { Octal, 8, "0o", x @ 0 ..= 7 => b'0' + x }
140radix! { LowerHex, 16, "0x", x @ 0 ..= 9 => b'0' + x, x @ 10 ..= 15 => b'a' + (x - 10) }
141radix! { UpperHex, 16, "0x", x @ 0 ..= 9 => b'0' + x, x @ 10 ..= 15 => b'A' + (x - 10) }
142
143macro_rules! int_base {
144 (fmt::$Trait:ident for $T:ident as $U:ident -> $Radix:ident) => {
145 #[stable(feature = "rust1", since = "1.0.0")]
146 impl fmt::$Trait for $T {
147 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
148 $Radix.fmt_int(*self as $U, f)
149 }
150 }
151 };
152}
153
154macro_rules! integer {
155 ($Int:ident, $Uint:ident) => {
156 int_base! { fmt::Binary for $Int as $Uint -> Binary }
157 int_base! { fmt::Octal for $Int as $Uint -> Octal }
158 int_base! { fmt::LowerHex for $Int as $Uint -> LowerHex }
159 int_base! { fmt::UpperHex for $Int as $Uint -> UpperHex }
160
161 int_base! { fmt::Binary for $Uint as $Uint -> Binary }
162 int_base! { fmt::Octal for $Uint as $Uint -> Octal }
163 int_base! { fmt::LowerHex for $Uint as $Uint -> LowerHex }
164 int_base! { fmt::UpperHex for $Uint as $Uint -> UpperHex }
165 };
166}
167integer! { isize, usize }
168integer! { i8, u8 }
169integer! { i16, u16 }
170integer! { i32, u32 }
171integer! { i64, u64 }
172integer! { i128, u128 }
173
174macro_rules! impl_Debug {
175 ($($T:ident)*) => {
176 $(
177 #[stable(feature = "rust1", since = "1.0.0")]
178 impl fmt::Debug for $T {
179 #[inline]
180 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
181 if f.debug_lower_hex() {
182 fmt::LowerHex::fmt(self, f)
183 } else if f.debug_upper_hex() {
184 fmt::UpperHex::fmt(self, f)
185 } else {
186 fmt::Display::fmt(self, f)
187 }
188 }
189 }
190 )*
191 };
192}
193
194static DEC_DIGITS_LUT: &[u8; 200] = b"\
196 0001020304050607080910111213141516171819\
197 2021222324252627282930313233343536373839\
198 4041424344454647484950515253545556575859\
199 6061626364656667686970717273747576777879\
200 8081828384858687888990919293949596979899";
201
202macro_rules! impl_Display {
203 ($($signed:ident, $unsigned:ident,)* ; as $u:ident via $conv_fn:ident named $gen_name:ident) => {
204
205 $(
206 #[stable(feature = "rust1", since = "1.0.0")]
207 impl fmt::Display for $unsigned {
208 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
209 #[cfg(not(feature = "optimize_for_size"))]
210 {
211 const MAX_DEC_N: usize = $unsigned::MAX.ilog10() as usize + 1;
212 let mut buf = [MaybeUninit::<u8>::uninit(); MAX_DEC_N];
214
215 f.pad_integral(true, "", self._fmt(&mut buf))
216 }
217 #[cfg(feature = "optimize_for_size")]
218 {
219 $gen_name(self.$conv_fn(), true, f)
220 }
221 }
222 }
223
224 #[stable(feature = "rust1", since = "1.0.0")]
225 impl fmt::Display for $signed {
226 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
227 #[cfg(not(feature = "optimize_for_size"))]
228 {
229 const MAX_DEC_N: usize = $unsigned::MAX.ilog10() as usize + 1;
230 let mut buf = [MaybeUninit::<u8>::uninit(); MAX_DEC_N];
232
233 f.pad_integral(*self >= 0, "", self.unsigned_abs()._fmt(&mut buf))
234 }
235 #[cfg(feature = "optimize_for_size")]
236 {
237 return $gen_name(self.unsigned_abs().$conv_fn(), *self >= 0, f);
238 }
239 }
240 }
241
242 #[cfg(not(feature = "optimize_for_size"))]
243 impl $unsigned {
244 #[doc(hidden)]
245 #[unstable(
246 feature = "fmt_internals",
247 reason = "specialized method meant to only be used by `SpecToString` implementation",
248 issue = "none"
249 )]
250 pub fn _fmt<'a>(self, buf: &'a mut [MaybeUninit::<u8>]) -> &'a str {
251 let mut offset = buf.len();
253 let mut remain = self;
255
256 while size_of::<Self>() > 1 && remain > 999.try_into().expect("branch is not hit for types that cannot fit 999 (u8)") {
259 unsafe { core::hint::assert_unchecked(offset >= 4) }
262 unsafe { core::hint::assert_unchecked(offset <= buf.len()) }
265 offset -= 4;
266
267 let scale: Self = 1_00_00.try_into().expect("branch is not hit for types that cannot fit 1E4 (u8)");
269 let quad = remain % scale;
270 remain /= scale;
271 let pair1 = (quad / 100) as usize;
272 let pair2 = (quad % 100) as usize;
273 buf[offset + 0].write(DEC_DIGITS_LUT[pair1 * 2 + 0]);
274 buf[offset + 1].write(DEC_DIGITS_LUT[pair1 * 2 + 1]);
275 buf[offset + 2].write(DEC_DIGITS_LUT[pair2 * 2 + 0]);
276 buf[offset + 3].write(DEC_DIGITS_LUT[pair2 * 2 + 1]);
277 }
278
279 if remain > 9 {
281 unsafe { core::hint::assert_unchecked(offset >= 2) }
284 unsafe { core::hint::assert_unchecked(offset <= buf.len()) }
287 offset -= 2;
288
289 let pair = (remain % 100) as usize;
290 remain /= 100;
291 buf[offset + 0].write(DEC_DIGITS_LUT[pair * 2 + 0]);
292 buf[offset + 1].write(DEC_DIGITS_LUT[pair * 2 + 1]);
293 }
294
295 if remain != 0 || self == 0 {
297 unsafe { core::hint::assert_unchecked(offset >= 1) }
300 unsafe { core::hint::assert_unchecked(offset <= buf.len()) }
303 offset -= 1;
304
305 let last = (remain & 15) as usize;
308 buf[offset].write(DEC_DIGITS_LUT[last * 2 + 1]);
309 }
311
312 let written = unsafe { buf.get_unchecked(offset..) };
314 unsafe {
316 str::from_utf8_unchecked(slice::from_raw_parts(
317 MaybeUninit::slice_as_ptr(written),
318 written.len(),
319 ))
320 }
321 }
322 })*
323
324 #[cfg(feature = "optimize_for_size")]
325 fn $gen_name(mut n: $u, is_nonnegative: bool, f: &mut fmt::Formatter<'_>) -> fmt::Result {
326 const MAX_DEC_N: usize = $u::MAX.ilog10() as usize + 1;
327 let mut buf = [MaybeUninit::<u8>::uninit(); MAX_DEC_N];
328 let mut curr = MAX_DEC_N;
329 let buf_ptr = MaybeUninit::slice_as_mut_ptr(&mut buf);
330
331 unsafe {
337 loop {
338 curr -= 1;
339 buf_ptr.add(curr).write((n % 10) as u8 + b'0');
340 n /= 10;
341
342 if n == 0 {
343 break;
344 }
345 }
346 }
347
348 let buf_slice = unsafe {
350 str::from_utf8_unchecked(
351 slice::from_raw_parts(buf_ptr.add(curr), buf.len() - curr))
352 };
353 f.pad_integral(is_nonnegative, "", buf_slice)
354 }
355 };
356}
357
358macro_rules! impl_Exp {
359 ($($t:ident),* as $u:ident via $conv_fn:ident named $name:ident) => {
360 fn $name(
361 mut n: $u,
362 is_nonnegative: bool,
363 upper: bool,
364 f: &mut fmt::Formatter<'_>
365 ) -> fmt::Result {
366 let (mut n, mut exponent, trailing_zeros, added_precision) = {
367 let mut exponent = 0;
368 while n % 10 == 0 && n >= 10 {
370 n /= 10;
371 exponent += 1;
372 }
373 let (added_precision, subtracted_precision) = match f.precision() {
374 Some(fmt_prec) => {
375 let mut tmp = n;
377 let mut prec = 0;
378 while tmp >= 10 {
379 tmp /= 10;
380 prec += 1;
381 }
382 (fmt_prec.saturating_sub(prec), prec.saturating_sub(fmt_prec))
383 }
384 None => (0, 0)
385 };
386 for _ in 1..subtracted_precision {
387 n /= 10;
388 exponent += 1;
389 }
390 if subtracted_precision != 0 {
391 let rem = n % 10;
392 n /= 10;
393 exponent += 1;
394 if rem > 5 || (rem == 5 && (n % 2 != 0 || subtracted_precision > 1 )) {
396 n += 1;
397 if n.ilog10() > (n - 1).ilog10() {
400 n /= 10;
401 exponent += 1;
402 }
403 }
404 }
405 (n, exponent, exponent, added_precision)
406 };
407
408 let mut buf = [MaybeUninit::<u8>::uninit(); 40];
411 let mut curr = buf.len(); let buf_ptr = MaybeUninit::slice_as_mut_ptr(&mut buf);
413 let lut_ptr = DEC_DIGITS_LUT.as_ptr();
414
415 while n >= 100 {
417 let d1 = ((n % 100) as usize) << 1;
418 curr -= 2;
419 unsafe {
422 ptr::copy_nonoverlapping(lut_ptr.add(d1), buf_ptr.add(curr), 2);
423 }
424 n /= 100;
425 exponent += 2;
426 }
427 let mut n = n as isize; if n >= 10 {
431 curr -= 1;
432 unsafe {
434 *buf_ptr.add(curr) = (n as u8 % 10_u8) + b'0';
435 }
436 n /= 10;
437 exponent += 1;
438 }
439 if exponent != trailing_zeros || added_precision != 0 {
441 curr -= 1;
442 unsafe {
444 *buf_ptr.add(curr) = b'.';
445 }
446 }
447
448 let buf_slice = unsafe {
450 curr -= 1;
452 *buf_ptr.add(curr) = (n as u8) + b'0';
453
454 let len = buf.len() - curr as usize;
455 slice::from_raw_parts(buf_ptr.add(curr), len)
456 };
457
458 let mut exp_buf = [MaybeUninit::<u8>::uninit(); 3];
460 let exp_ptr = MaybeUninit::slice_as_mut_ptr(&mut exp_buf);
461 let exp_slice = unsafe {
464 *exp_ptr.add(0) = if upper { b'E' } else { b'e' };
465 let len = if exponent < 10 {
466 *exp_ptr.add(1) = (exponent as u8) + b'0';
467 2
468 } else {
469 let off = exponent << 1;
470 ptr::copy_nonoverlapping(lut_ptr.add(off), exp_ptr.add(1), 2);
471 3
472 };
473 slice::from_raw_parts(exp_ptr, len)
474 };
475
476 let parts = &[
477 numfmt::Part::Copy(buf_slice),
478 numfmt::Part::Zero(added_precision),
479 numfmt::Part::Copy(exp_slice),
480 ];
481 let sign = if !is_nonnegative {
482 "-"
483 } else if f.sign_plus() {
484 "+"
485 } else {
486 ""
487 };
488 let formatted = numfmt::Formatted { sign, parts };
489 unsafe { f.pad_formatted_parts(&formatted) }
491 }
492
493 $(
494 #[stable(feature = "integer_exp_format", since = "1.42.0")]
495 impl fmt::LowerExp for $t {
496 #[allow(unused_comparisons)]
497 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
498 let is_nonnegative = *self >= 0;
499 let n = if is_nonnegative {
500 self.$conv_fn()
501 } else {
502 (!self.$conv_fn()).wrapping_add(1)
504 };
505 $name(n, is_nonnegative, false, f)
506 }
507 })*
508 $(
509 #[stable(feature = "integer_exp_format", since = "1.42.0")]
510 impl fmt::UpperExp for $t {
511 #[allow(unused_comparisons)]
512 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
513 let is_nonnegative = *self >= 0;
514 let n = if is_nonnegative {
515 self.$conv_fn()
516 } else {
517 (!self.$conv_fn()).wrapping_add(1)
519 };
520 $name(n, is_nonnegative, true, f)
521 }
522 })*
523 };
524}
525
526impl_Debug! {
527 i8 i16 i32 i64 i128 isize
528 u8 u16 u32 u64 u128 usize
529}
530
531#[cfg(any(target_pointer_width = "64", target_arch = "wasm32"))]
534mod imp {
535 use super::*;
536 impl_Display!(
537 i8, u8,
538 i16, u16,
539 i32, u32,
540 i64, u64,
541 isize, usize,
542 ; as u64 via to_u64 named fmt_u64
543 );
544 impl_Exp!(
545 i8, u8, i16, u16, i32, u32, i64, u64, usize, isize
546 as u64 via to_u64 named exp_u64
547 );
548}
549
550#[cfg(not(any(target_pointer_width = "64", target_arch = "wasm32")))]
551mod imp {
552 use super::*;
553 impl_Display!(
554 i8, u8,
555 i16, u16,
556 i32, u32,
557 isize, usize,
558 ; as u32 via to_u32 named fmt_u32);
559 impl_Display!(
560 i64, u64,
561 ; as u64 via to_u64 named fmt_u64);
562
563 impl_Exp!(i8, u8, i16, u16, i32, u32, isize, usize as u32 via to_u32 named exp_u32);
564 impl_Exp!(i64, u64 as u64 via to_u64 named exp_u64);
565}
566impl_Exp!(i128, u128 as u128 via to_u128 named exp_u128);
567
568const U128_MAX_DEC_N: usize = u128::MAX.ilog10() as usize + 1;
569
570#[stable(feature = "rust1", since = "1.0.0")]
571impl fmt::Display for u128 {
572 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
573 let mut buf = [MaybeUninit::<u8>::uninit(); U128_MAX_DEC_N];
574
575 f.pad_integral(true, "", self._fmt(&mut buf))
576 }
577}
578
579#[stable(feature = "rust1", since = "1.0.0")]
580impl fmt::Display for i128 {
581 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
582 let mut buf = [MaybeUninit::<u8>::uninit(); U128_MAX_DEC_N];
585
586 let is_nonnegative = *self >= 0;
587 f.pad_integral(is_nonnegative, "", self.unsigned_abs()._fmt(&mut buf))
588 }
589}
590
591impl u128 {
592 #[doc(hidden)]
595 #[unstable(
596 feature = "fmt_internals",
597 reason = "specialized method meant to only be used by `SpecToString` implementation",
598 issue = "none"
599 )]
600 pub fn _fmt<'a>(self, buf: &'a mut [MaybeUninit<u8>]) -> &'a str {
601 if self == 0 {
604 return "0";
605 }
606
607 let (quot_1e16, mod_1e16) = div_rem_1e16(self);
609 let (mut remain, mut offset) = if quot_1e16 == 0 {
610 (mod_1e16, U128_MAX_DEC_N)
611 } else {
612 enc_16lsd::<{ U128_MAX_DEC_N - 16 }>(buf, mod_1e16);
614
615 let (quot2, mod2) = div_rem_1e16(quot_1e16);
617 if quot2 == 0 {
618 (mod2, U128_MAX_DEC_N - 16)
619 } else {
620 enc_16lsd::<{ U128_MAX_DEC_N - 32 }>(buf, mod2);
622 (quot2 as u64, U128_MAX_DEC_N - 32)
624 }
625 };
626
627 while remain > 999 {
629 unsafe { core::hint::assert_unchecked(offset >= 4) }
632 unsafe { core::hint::assert_unchecked(offset <= buf.len()) }
635 offset -= 4;
636
637 let quad = remain % 1_00_00;
639 remain /= 1_00_00;
640 let pair1 = (quad / 100) as usize;
641 let pair2 = (quad % 100) as usize;
642 buf[offset + 0].write(DEC_DIGITS_LUT[pair1 * 2 + 0]);
643 buf[offset + 1].write(DEC_DIGITS_LUT[pair1 * 2 + 1]);
644 buf[offset + 2].write(DEC_DIGITS_LUT[pair2 * 2 + 0]);
645 buf[offset + 3].write(DEC_DIGITS_LUT[pair2 * 2 + 1]);
646 }
647
648 if remain > 9 {
650 unsafe { core::hint::assert_unchecked(offset >= 2) }
653 unsafe { core::hint::assert_unchecked(offset <= buf.len()) }
656 offset -= 2;
657
658 let pair = (remain % 100) as usize;
659 remain /= 100;
660 buf[offset + 0].write(DEC_DIGITS_LUT[pair * 2 + 0]);
661 buf[offset + 1].write(DEC_DIGITS_LUT[pair * 2 + 1]);
662 }
663
664 if remain != 0 {
666 unsafe { core::hint::assert_unchecked(offset >= 1) }
669 unsafe { core::hint::assert_unchecked(offset <= buf.len()) }
672 offset -= 1;
673
674 let last = (remain & 15) as usize;
677 buf[offset].write(DEC_DIGITS_LUT[last * 2 + 1]);
678 }
680
681 let written = unsafe { buf.get_unchecked(offset..) };
683 unsafe {
685 str::from_utf8_unchecked(slice::from_raw_parts(
686 MaybeUninit::slice_as_ptr(written),
687 written.len(),
688 ))
689 }
690 }
691}
692
693fn enc_16lsd<const OFFSET: usize>(buf: &mut [MaybeUninit<u8>], n: u64) {
696 let mut remain = n;
698
699 for quad_index in (0..4).rev() {
701 let quad = remain % 1_00_00;
703 remain /= 1_00_00;
704 let pair1 = (quad / 100) as usize;
705 let pair2 = (quad % 100) as usize;
706 buf[quad_index * 4 + OFFSET + 0].write(DEC_DIGITS_LUT[pair1 * 2 + 0]);
707 buf[quad_index * 4 + OFFSET + 1].write(DEC_DIGITS_LUT[pair1 * 2 + 1]);
708 buf[quad_index * 4 + OFFSET + 2].write(DEC_DIGITS_LUT[pair2 * 2 + 0]);
709 buf[quad_index * 4 + OFFSET + 3].write(DEC_DIGITS_LUT[pair2 * 2 + 1]);
710 }
711}
712
713#[inline]
723fn div_rem_1e16(n: u128) -> (u128, u64) {
724 const D: u128 = 1_0000_0000_0000_0000;
725 if n < D {
727 return (0, n as u64);
728 }
729
730 const M_HIGH: u128 = 76624777043294442917917351357515459181;
733 const SH_POST: u8 = 51;
734
735 let quot = n.widening_mul(M_HIGH).1 >> SH_POST;
736 let rem = n - quot * D;
737 (quot, rem as u64)
738}