@@ -10,9 +10,6 @@ use crate::{fmt, ptr, slice, str};
1010trait  DisplayInt : 
1111    PartialEq  + PartialOrd  + Div < Output  = Self >  + Rem < Output  = Self >  + Sub < Output  = Self >  + Copy 
1212{ 
13-     fn  zero ( )  -> Self ; 
14-     fn  from_u8 ( u :  u8 )  -> Self ; 
15-     fn  to_u8 ( & self )  -> u8 ; 
1613    #[ cfg( not( any( target_pointer_width = "64" ,  target_arch = "wasm32" ) ) ) ]  
1714    fn  to_u32 ( & self )  -> u32 ; 
1815    fn  to_u64 ( & self )  -> u64 ; 
@@ -22,9 +19,6 @@ trait DisplayInt:
2219macro_rules!  impl_int { 
2320    ( $( $t: ident) * )  => ( 
2421        $( 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  } 
2822            #[ cfg( not( any( target_pointer_width = "64" ,  target_arch = "wasm32" ) ) ) ] 
2923            fn  to_u32( & self )  -> u32  {  * self  as  u32  } 
3024            fn  to_u64( & self )  -> u64  {  * self  as  u64  } 
@@ -38,137 +32,80 @@ impl_int! {
3832    u8  u16  u32  u64  u128  usize 
3933} 
4034
41- /// A type that represents a specific radix 
42- /// 
43- /// # Safety 
44- /// 
45- /// `digit` must return an ASCII character. 
46- #[ doc( hidden) ]  
47- unsafe  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 unsigned 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  mut  buf = [ MaybeUninit :: < u8 > :: uninit ( ) ;  128 ] ; 
63-         let  mut  offset = buf. len ( ) ; 
64-         let  base = T :: from_u8 ( Self :: BASE ) ; 
65- 
66-         // Accumulate each digit of the number from the least significant 
67-         // to the most significant figure. 
68-         loop  { 
69-             let  n = x % base;  // Get the current place value. 
70-             x = x / base;  // Deaccumulate the number. 
71-             offset -= 1 ; 
72-             buf[ offset] . write ( Self :: digit ( n. to_u8 ( ) ) ) ;  // Store the digit in the buffer. 
73-             if  x == zero { 
74-                 // No more digits left to accumulate. 
75-                 break ; 
76-             } ; 
77-         } 
35+ // Formatting of integers with a non-decimal radix. 
36+ macro_rules!  radix_integer { 
37+     ( fmt:: $Trait: ident for  $Signed: ident and $Unsigned: ident,  $prefix: expr,  $dig_tab: expr)  => { 
38+         #[ stable( feature = "rust1" ,  since = "1.0.0" ) ] 
39+         impl  fmt:: $Trait for  $Unsigned { 
40+             /// Format unsigned integers in the radix. 
41+ fn  fmt( & self ,  f:  & mut  fmt:: Formatter <' _>)  -> fmt:: Result  { 
42+                 // Check arguments at compile time. 
43+                 assert!( $Unsigned:: MIN  == 0 ) ; 
44+                 $dig_tab. as_ascii( ) . unwrap( ) ; 
7845
79-         // SAFETY: Starting from `offset`, all elements of the slice have been set. 
80-         let  digits = unsafe  {  slice_buffer_to_str ( & buf,  offset)  } ; 
81-         f. pad_integral ( true ,  Self :: PREFIX ,  digits) 
82-     } 
83- } 
46+                 // ASCII digits in ascending order are used as a lookup table. 
47+                 const  DIG_TAB :  & [ u8 ]  = $dig_tab; 
48+                 const  BASE :  $Unsigned = DIG_TAB . len( )  as  $Unsigned; 
49+                 const  MAX_DIG_N :  usize  = $Unsigned:: MAX . ilog( BASE )  as  usize  + 1 ; 
8450
85- /// A binary (base 2) radix 
86- #[ derive( Clone ,  PartialEq ) ]  
87- struct  Binary ; 
88- 
89- /// An octal (base 8) radix 
90- #[ derive( Clone ,  PartialEq ) ]  
91- struct  Octal ; 
92- 
93- /// A hexadecimal (base 16) radix, formatted with lower-case characters 
94- #[ derive( Clone ,  PartialEq ) ]  
95- struct  LowerHex ; 
96- 
97- /// A hexadecimal (base 16) radix, formatted with upper-case characters 
98- #[ derive( Clone ,  PartialEq ) ]  
99- struct  UpperHex ; 
100- 
101- macro_rules!  radix { 
102-     ( $T: ident,  $base: expr,  $prefix: expr,  $( $x: pat => $conv: expr) ,+)  => { 
103-         unsafe  impl  GenericRadix  for  $T { 
104-             const  BASE :  u8  = $base; 
105-             const  PREFIX :  & ' static  str  = $prefix; 
106-             fn  digit( x:  u8 )  -> u8  { 
107-                 match  x { 
108-                     $( $x => $conv, ) +
109-                     x => panic!( "number not in the range 0..={}: {}" ,  Self :: BASE  - 1 ,  x) , 
51+                 // Buffer digits of self with right alignment. 
52+                 let  mut  buf = [ MaybeUninit :: <u8 >:: uninit( ) ;  MAX_DIG_N ] ; 
53+                 // Count the number of bytes in buf that are not initialized. 
54+                 let  mut  offset = buf. len( ) ; 
55+ 
56+                 // Accumulate each digit of the number from the least 
57+                 // significant to the most significant figure. 
58+                 let  mut  remain = * self ; 
59+                 loop  { 
60+                     let  digit = remain % BASE ; 
61+                     remain /= BASE ; 
62+ 
63+                     // SAFETY: All of the decimals fit in buf due to MAX_DEC_N 
64+                     // and the break condition below ensures at least 1 more 
65+                     // decimal. 
66+                     unsafe  {  core:: hint:: assert_unchecked( offset >= 1 )  } 
67+                     // SAFETY: The offset counts down from its initial buf.len() 
68+                     // without underflow due to the previous precondition. 
69+                     unsafe  {  core:: hint:: assert_unchecked( offset <= buf. len( ) )  } 
70+                     offset -= 1 ; 
71+                     buf[ offset] . write( DIG_TAB [ digit as  usize ] ) ; 
72+                     if  remain == 0  { 
73+                         break ; 
74+                     } 
11075                } 
76+ 
77+                 // SAFETY: Starting from `offset`, all elements of the slice have been set. 
78+                 let  digits = unsafe  {  slice_buffer_to_str( & buf,  offset)  } ; 
79+                 f. pad_integral( true ,  $prefix,  digits) 
11180            } 
11281        } 
113-     } 
114- } 
115- 
116- radix !  {  Binary ,     2 ,  "0b" ,  x @  0  ..=  1  => b'0'  + x } 
117- radix !  {  Octal ,      8 ,  "0o" ,  x @  0  ..=  7  => b'0'  + x } 
118- radix !  {  LowerHex ,  16 ,  "0x" ,  x @  0  ..=  9  => b'0'  + x,  x @ 10  ..= 15  => b'a'  + ( x - 10 )  } 
119- radix !  {  UpperHex ,  16 ,  "0x" ,  x @  0  ..=  9  => b'0'  + x,  x @ 10  ..= 15  => b'A'  + ( x - 10 )  } 
12082
121- macro_rules!  int_base { 
122-     ( fmt:: $Trait: ident for  $T: ident -> $Radix: ident)  => { 
12383        #[ stable( feature = "rust1" ,  since = "1.0.0" ) ] 
124-         impl  fmt:: $Trait for  $T { 
84+         impl  fmt:: $Trait for  $Signed { 
85+             /// Format signed integers in the two’s-complement form. 
12586fn  fmt( & self ,  f:  & mut  fmt:: Formatter <' _>)  -> fmt:: Result  { 
126-                 $Radix. fmt_int( * self ,  f) 
87+                 assert!( $Signed:: MIN  < 0 ) ; 
88+                 fmt:: $Trait:: fmt( & ( * self  as  $Unsigned) ,  f) 
12789            } 
12890        } 
12991    } ; 
13092} 
13193
132- macro_rules!  integer { 
133-     ( $Int: ident,  $Uint: ident)  => { 
134-         int_base! {  fmt:: Binary    for  $Uint -> Binary  } 
135-         int_base! {  fmt:: Octal     for  $Uint -> Octal  } 
136-         int_base! {  fmt:: LowerHex  for  $Uint -> LowerHex  } 
137-         int_base! {  fmt:: UpperHex  for  $Uint -> UpperHex  } 
138- 
139-         // Format signed integers as unsigned (two’s complement representation). 
140-         #[ stable( feature = "rust1" ,  since = "1.0.0" ) ] 
141-         impl  fmt:: Binary  for  $Int { 
142-             fn  fmt( & self ,  f:  & mut  fmt:: Formatter <' _>)  -> fmt:: Result  { 
143-                 fmt:: Binary :: fmt( & ( * self  as  $Uint) ,  f) 
144-             } 
145-         } 
146-         #[ stable( feature = "rust1" ,  since = "1.0.0" ) ] 
147-         impl  fmt:: Octal  for  $Int { 
148-             fn  fmt( & self ,  f:  & mut  fmt:: Formatter <' _>)  -> fmt:: Result  { 
149-                 fmt:: Octal :: fmt( & ( * self  as  $Uint) ,  f) 
150-             } 
151-         } 
152-         #[ stable( feature = "rust1" ,  since = "1.0.0" ) ] 
153-         impl  fmt:: LowerHex  for  $Int { 
154-             fn  fmt( & self ,  f:  & mut  fmt:: Formatter <' _>)  -> fmt:: Result  { 
155-                 fmt:: LowerHex :: fmt( & ( * self  as  $Uint) ,  f) 
156-             } 
157-         } 
158-         #[ stable( feature = "rust1" ,  since = "1.0.0" ) ] 
159-         impl  fmt:: UpperHex  for  $Int { 
160-             fn  fmt( & self ,  f:  & mut  fmt:: Formatter <' _>)  -> fmt:: Result  { 
161-                 fmt:: UpperHex :: fmt( & ( * self  as  $Uint) ,  f) 
162-             } 
163-         } 
94+ // Formatting of integers with a non-decimal radix. 
95+ macro_rules!  radix_integers { 
96+     ( $Signed: ident,  $Unsigned: ident)  => { 
97+         radix_integer! {  fmt:: Binary    for  $Signed and $Unsigned,  "0b" ,  b"01"  } 
98+         radix_integer! {  fmt:: Octal     for  $Signed and $Unsigned,  "0o" ,  b"01234567"  } 
99+         radix_integer! {  fmt:: LowerHex  for  $Signed and $Unsigned,  "0x" ,  b"0123456789abcdef"  } 
100+         radix_integer! {  fmt:: UpperHex  for  $Signed and $Unsigned,  "0x" ,  b"0123456789ABCDEF"  } 
164101    } ; 
165102} 
166- integer !  {  isize ,  usize  } 
167- integer !  {  i8 ,  u8  } 
168- integer !  {  i16 ,  u16  } 
169- integer !  {  i32 ,  u32  } 
170- integer !  {  i64 ,  u64  } 
171- integer !  {  i128 ,  u128  } 
103+ radix_integers !  {  isize ,  usize  } 
104+ radix_integers !  {  i8 ,  u8  } 
105+ radix_integers !  {  i16 ,  u16  } 
106+ radix_integers !  {  i32 ,  u32  } 
107+ radix_integers !  {  i64 ,  u64  } 
108+ radix_integers !  {  i128 ,  u128  } 
172109
173110macro_rules!  impl_Debug { 
174111    ( $( $T: ident) * )  => { 
0 commit comments