diff options
| author | Pascal S. de Kloe <pascal@quies.net> | 2025-07-10 14:32:02 +0200 |
|---|---|---|
| committer | Pascal S. de Kloe <pascal@quies.net> | 2025-08-16 18:33:20 +0200 |
| commit | 1f77424a7902e0e0a5cdbbe650394a14f61637d0 (patch) | |
| tree | 1250743a9280420638d347ff5fc180a6ef807255 | |
| parent | 4ad8606d79a7cb9693f315fdd979fdb03d72318e (diff) | |
| download | rust-1f77424a7902e0e0a5cdbbe650394a14f61637d0.tar.gz rust-1f77424a7902e0e0a5cdbbe650394a14f61637d0.zip | |
fmt::DisplayInt abstraction obsolete with better macro
| -rw-r--r-- | library/core/src/fmt/num.rs | 166 |
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; |
