about summary refs log tree commit diff
diff options
context:
space:
mode:
authorPascal S. de Kloe <pascal@quies.net>2025-07-10 14:32:02 +0200
committerPascal S. de Kloe <pascal@quies.net>2025-08-16 18:33:20 +0200
commit1f77424a7902e0e0a5cdbbe650394a14f61637d0 (patch)
tree1250743a9280420638d347ff5fc180a6ef807255
parent4ad8606d79a7cb9693f315fdd979fdb03d72318e (diff)
downloadrust-1f77424a7902e0e0a5cdbbe650394a14f61637d0.tar.gz
rust-1f77424a7902e0e0a5cdbbe650394a14f61637d0.zip
fmt::DisplayInt abstraction obsolete with better macro
-rw-r--r--library/core/src/fmt/num.rs166
1 files changed, 72 insertions, 94 deletions
diff --git a/library/core/src/fmt/num.rs b/library/core/src/fmt/num.rs
index cdabaeb7265..605ba42c541 100644
--- a/library/core/src/fmt/num.rs
+++ b/library/core/src/fmt/num.rs
@@ -3,35 +3,8 @@
 use crate::fmt::NumBuffer;
 use crate::mem::MaybeUninit;
 use crate::num::fmt as numfmt;
-use crate::ops::{Div, Rem, Sub};
 use crate::{fmt, ptr, slice, str};
 
-#[doc(hidden)]
-trait DisplayInt:
-    PartialEq + PartialOrd + Div<Output = Self> + Rem<Output = Self> + Sub<Output = Self> + Copy
-{
-    #[cfg(not(any(target_pointer_width = "64", target_arch = "wasm32")))]
-    fn to_u32(&self) -> u32;
-    fn to_u64(&self) -> u64;
-    fn to_u128(&self) -> u128;
-}
-
-macro_rules! impl_int {
-    ($($t:ident)*) => (
-        $(impl DisplayInt for $t {
-            #[cfg(not(any(target_pointer_width = "64", target_arch = "wasm32")))]
-            fn to_u32(&self) -> u32 { *self as u32 }
-            fn to_u64(&self) -> u64 { *self as u64 }
-            fn to_u128(&self) -> u128 { *self as u128 }
-        })*
-    )
-}
-
-impl_int! {
-    i8 i16 i32 i64 i128 isize
-    u8 u16 u32 u64 u128 usize
-}
-
 /// Formatting of integers with a non-decimal radix.
 macro_rules! radix_integer {
     (fmt::$Trait:ident for $Signed:ident and $Unsigned:ident, $prefix:literal, $dig_tab:literal) => {
@@ -146,16 +119,21 @@ unsafe fn slice_buffer_to_str(buf: &[MaybeUninit<u8>], offset: usize) -> &str {
 }
 
 macro_rules! impl_Display {
-    ($($signed:ident, $unsigned:ident,)* ; as $u:ident via $conv_fn:ident named $gen_name:ident) => {
+    ($($Signed:ident, $Unsigned:ident),* ; as $T:ident into $fmt_fn:ident) => {
 
         $(
+        const _: () = {
+            assert!($Signed::BITS <= $T::BITS, "need lossless conversion");
+            assert!($Unsigned::BITS <= $T::BITS, "need lossless conversion");
+        };
+
         #[stable(feature = "rust1", since = "1.0.0")]
-        impl fmt::Display for $unsigned {
+        impl fmt::Display for $Unsigned {
             fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
                 #[cfg(not(feature = "optimize_for_size"))]
                 {
-                    const MAX_DEC_N: usize = $unsigned::MAX.ilog10() as usize + 1;
-                    // Buffer decimals for $unsigned with right alignment.
+                    const MAX_DEC_N: usize = $Unsigned::MAX.ilog10() as usize + 1;
+                    // Buffer decimals for self with right alignment.
                     let mut buf = [MaybeUninit::<u8>::uninit(); MAX_DEC_N];
 
                     // SAFETY: `buf` is always big enough to contain all the digits.
@@ -163,18 +141,20 @@ macro_rules! impl_Display {
                 }
                 #[cfg(feature = "optimize_for_size")]
                 {
-                    $gen_name(self.$conv_fn(), true, f)
+                    // Lossless conversion (with as) is asserted at the top of
+                    // this macro.
+                    ${concat($fmt_fn, _small)}(*self as $T, true, f)
                 }
             }
         }
 
         #[stable(feature = "rust1", since = "1.0.0")]
-        impl fmt::Display for $signed {
+        impl fmt::Display for $Signed {
             fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
                 #[cfg(not(feature = "optimize_for_size"))]
                 {
-                    const MAX_DEC_N: usize = $unsigned::MAX.ilog10() as usize + 1;
-                    // Buffer decimals for $unsigned with right alignment.
+                    const MAX_DEC_N: usize = $Unsigned::MAX.ilog10() as usize + 1;
+                    // Buffer decimals for self with right alignment.
                     let mut buf = [MaybeUninit::<u8>::uninit(); MAX_DEC_N];
 
                     // SAFETY: `buf` is always big enough to contain all the digits.
@@ -182,13 +162,15 @@ macro_rules! impl_Display {
                 }
                 #[cfg(feature = "optimize_for_size")]
                 {
-                    return $gen_name(self.unsigned_abs().$conv_fn(), *self >= 0, f);
+                    // Lossless conversion (with as) is asserted at the top of
+                    // this macro.
+                    return ${concat($fmt_fn, _small)}(self.unsigned_abs() as $T, *self >= 0, f);
                 }
             }
         }
 
         #[cfg(not(feature = "optimize_for_size"))]
-        impl $unsigned {
+        impl $Unsigned {
             #[doc(hidden)]
             #[unstable(
                 feature = "fmt_internals",
@@ -209,7 +191,7 @@ macro_rules! impl_Display {
                 let mut remain = self;
 
                 // Format per four digits from the lookup table.
-                // Four digits need a 16-bit $unsigned or wider.
+                // Four digits need a 16-bit $Unsigned or wider.
                 while size_of::<Self>() > 1 && remain > 999.try_into().expect("branch is not hit for types that cannot fit 999 (u8)") {
                     // SAFETY: All of the decimals fit in buf due to MAX_DEC_N
                     // and the while condition ensures at least 4 more decimals.
@@ -268,7 +250,7 @@ macro_rules! impl_Display {
             }
         }
 
-        impl $signed {
+        impl $Signed {
             /// Allows users to write an integer (in signed decimal format) into a variable `buf` of
             /// type [`NumBuffer`] that is passed by the caller by mutable reference.
             ///
@@ -278,15 +260,15 @@ macro_rules! impl_Display {
             /// #![feature(int_format_into)]
             /// use core::fmt::NumBuffer;
             ///
-            #[doc = concat!("let n = 0", stringify!($signed), ";")]
+            #[doc = concat!("let n = 0", stringify!($Signed), ";")]
             /// let mut buf = NumBuffer::new();
             /// assert_eq!(n.format_into(&mut buf), "0");
             ///
-            #[doc = concat!("let n1 = 32", stringify!($signed), ";")]
+            #[doc = concat!("let n1 = 32", stringify!($Signed), ";")]
             /// assert_eq!(n1.format_into(&mut buf), "32");
             ///
-            #[doc = concat!("let n2 = ", stringify!($signed::MAX), ";")]
-            #[doc = concat!("assert_eq!(n2.format_into(&mut buf), ", stringify!($signed::MAX), ".to_string());")]
+            #[doc = concat!("let n2 = ", stringify!($Signed::MAX), ";")]
+            #[doc = concat!("assert_eq!(n2.format_into(&mut buf), ", stringify!($Signed::MAX), ".to_string());")]
             /// ```
             #[unstable(feature = "int_format_into", issue = "138215")]
             pub fn format_into(self, buf: &mut NumBuffer<Self>) -> &str {
@@ -299,7 +281,9 @@ macro_rules! impl_Display {
                 }
                 #[cfg(feature = "optimize_for_size")]
                 {
-                    offset = ${concat(_inner_slow_integer_to_str, $gen_name)}(self.unsigned_abs().$conv_fn(), &mut buf.buf);
+                    // Lossless conversion (with as) is asserted at the top of
+                    // this macro.
+                    offset = ${concat($fmt_fn, _in_buf_small)}(self.unsigned_abs() as $T, &mut buf.buf);
                 }
                 // Only difference between signed and unsigned are these 4 lines.
                 if self < 0 {
@@ -311,7 +295,7 @@ macro_rules! impl_Display {
             }
         }
 
-        impl $unsigned {
+        impl $Unsigned {
             /// Allows users to write an integer (in signed decimal format) into a variable `buf` of
             /// type [`NumBuffer`] that is passed by the caller by mutable reference.
             ///
@@ -321,15 +305,15 @@ macro_rules! impl_Display {
             /// #![feature(int_format_into)]
             /// use core::fmt::NumBuffer;
             ///
-            #[doc = concat!("let n = 0", stringify!($unsigned), ";")]
+            #[doc = concat!("let n = 0", stringify!($Unsigned), ";")]
             /// let mut buf = NumBuffer::new();
             /// assert_eq!(n.format_into(&mut buf), "0");
             ///
-            #[doc = concat!("let n1 = 32", stringify!($unsigned), ";")]
+            #[doc = concat!("let n1 = 32", stringify!($Unsigned), ";")]
             /// assert_eq!(n1.format_into(&mut buf), "32");
             ///
-            #[doc = concat!("let n2 = ", stringify!($unsigned::MAX), ";")]
-            #[doc = concat!("assert_eq!(n2.format_into(&mut buf), ", stringify!($unsigned::MAX), ".to_string());")]
+            #[doc = concat!("let n2 = ", stringify!($Unsigned::MAX), ";")]
+            #[doc = concat!("assert_eq!(n2.format_into(&mut buf), ", stringify!($Unsigned::MAX), ".to_string());")]
             /// ```
             #[unstable(feature = "int_format_into", issue = "138215")]
             pub fn format_into(self, buf: &mut NumBuffer<Self>) -> &str {
@@ -342,7 +326,9 @@ macro_rules! impl_Display {
                 }
                 #[cfg(feature = "optimize_for_size")]
                 {
-                    offset = ${concat(_inner_slow_integer_to_str, $gen_name)}(self.$conv_fn(), &mut buf.buf);
+                    // Lossless conversion (with as) is asserted at the top of
+                    // this macro.
+                    offset = ${concat($fmt_fn, _in_buf_small)}(self as $T, &mut buf.buf);
                 }
                 // SAFETY: Starting from `offset`, all elements of the slice have been set.
                 unsafe { slice_buffer_to_str(&buf.buf, offset) }
@@ -353,7 +339,7 @@ macro_rules! impl_Display {
         )*
 
         #[cfg(feature = "optimize_for_size")]
-        fn ${concat(_inner_slow_integer_to_str, $gen_name)}(mut n: $u, buf: &mut [MaybeUninit::<u8>]) -> usize {
+        fn ${concat($fmt_fn, _in_buf_small)}(mut n: $T, buf: &mut [MaybeUninit::<u8>]) -> usize {
             let mut curr = buf.len();
 
             // SAFETY: To show that it's OK to copy into `buf_ptr`, notice that at the beginning
@@ -374,11 +360,11 @@ macro_rules! impl_Display {
         }
 
         #[cfg(feature = "optimize_for_size")]
-        fn $gen_name(n: $u, is_nonnegative: bool, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-            const MAX_DEC_N: usize = $u::MAX.ilog(10) as usize + 1;
+        fn ${concat($fmt_fn, _small)}(n: $T, is_nonnegative: bool, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+            const MAX_DEC_N: usize = $T::MAX.ilog(10) as usize + 1;
             let mut buf = [MaybeUninit::<u8>::uninit(); MAX_DEC_N];
 
-            let offset = ${concat(_inner_slow_integer_to_str, $gen_name)}(n, &mut buf);
+            let offset = ${concat($fmt_fn, _in_buf_small)}(n, &mut buf);
             // SAFETY: Starting from `offset`, all elements of the slice have been set.
             let buf_slice = unsafe { slice_buffer_to_str(&buf, offset) };
             f.pad_integral(is_nonnegative, "", buf_slice)
@@ -387,9 +373,9 @@ macro_rules! impl_Display {
 }
 
 macro_rules! impl_Exp {
-    ($($t:ident),* as $u:ident via $conv_fn:ident named $name:ident) => {
-        fn $name(
-            mut n: $u,
+    ($($Signed:ident, $Unsigned:ident),* ; as $T:ident into $fmt_fn:ident) => {
+        fn $fmt_fn(
+            mut n: $T,
             is_nonnegative: bool,
             upper: bool,
             f: &mut fmt::Formatter<'_>
@@ -523,32 +509,41 @@ macro_rules! impl_Exp {
 
         $(
             #[stable(feature = "integer_exp_format", since = "1.42.0")]
-            impl fmt::LowerExp for $t {
-                #[allow(unused_comparisons)]
+            impl fmt::LowerExp for $Signed {
                 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
                     let is_nonnegative = *self >= 0;
                     let n = if is_nonnegative {
-                        self.$conv_fn()
+                        *self as $T
                     } else {
-                        // convert the negative num to positive by summing 1 to its 2s complement
-                        (!self.$conv_fn()).wrapping_add(1)
+                        self.unsigned_abs() as $T
                     };
-                    $name(n, is_nonnegative, false, f)
+                    $fmt_fn(n, is_nonnegative, false, f)
+                }
+            }
+            #[stable(feature = "integer_exp_format", since = "1.42.0")]
+            impl fmt::LowerExp for $Unsigned {
+                fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+                    $fmt_fn(*self as $T, true, false, f)
                 }
             })*
+
         $(
             #[stable(feature = "integer_exp_format", since = "1.42.0")]
-            impl fmt::UpperExp for $t {
-                #[allow(unused_comparisons)]
+            impl fmt::UpperExp for $Signed {
                 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
                     let is_nonnegative = *self >= 0;
                     let n = if is_nonnegative {
-                        self.$conv_fn()
+                        *self as $T
                     } else {
-                        // convert the negative num to positive by summing 1 to its 2s complement
-                        (!self.$conv_fn()).wrapping_add(1)
+                        self.unsigned_abs() as $T
                     };
-                    $name(n, is_nonnegative, true, f)
+                    $fmt_fn(n, is_nonnegative, true, f)
+                }
+            }
+            #[stable(feature = "integer_exp_format", since = "1.42.0")]
+            impl fmt::UpperExp for $Unsigned {
+                fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+                    $fmt_fn(*self as $T, true, true, f)
                 }
             })*
     };
@@ -564,37 +559,20 @@ impl_Debug! {
 #[cfg(any(target_pointer_width = "64", target_arch = "wasm32"))]
 mod imp {
     use super::*;
-    impl_Display!(
-        i8, u8,
-        i16, u16,
-        i32, u32,
-        i64, u64,
-        isize, usize,
-        ; as u64 via to_u64 named fmt_u64
-    );
-    impl_Exp!(
-        i8, u8, i16, u16, i32, u32, i64, u64, usize, isize
-            as u64 via to_u64 named exp_u64
-    );
+    impl_Display!(i8, u8, i16, u16, i32, u32, i64, u64, isize, usize; as u64 into display_u64);
+    impl_Exp!(i8, u8, i16, u16, i32, u32, i64, u64, isize, usize; as u64 into exp_u64);
 }
 
 #[cfg(not(any(target_pointer_width = "64", target_arch = "wasm32")))]
 mod imp {
     use super::*;
-    impl_Display!(
-        i8, u8,
-        i16, u16,
-        i32, u32,
-        isize, usize,
-        ; as u32 via to_u32 named fmt_u32);
-    impl_Display!(
-        i64, u64,
-        ; as u64 via to_u64 named fmt_u64);
-
-    impl_Exp!(i8, u8, i16, u16, i32, u32, isize, usize as u32 via to_u32 named exp_u32);
-    impl_Exp!(i64, u64 as u64 via to_u64 named exp_u64);
+    impl_Display!(i8, u8, i16, u16, i32, u32, isize, usize; as u32 into display_u32);
+    impl_Display!(i64, u64; as u64 into display_u64);
+
+    impl_Exp!(i8, u8, i16, u16, i32, u32, isize, usize; as u32 into exp_u32);
+    impl_Exp!(i64, u64; as u64 into exp_u64);
 }
-impl_Exp!(i128, u128 as u128 via to_u128 named exp_u128);
+impl_Exp!(i128, u128; as u128 into exp_u128);
 
 const U128_MAX_DEC_N: usize = u128::MAX.ilog10() as usize + 1;