From 381fec2c8b8d25854cee57fb71d87b7ddc993ac8 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Tue, 8 Jul 2025 14:18:30 +0200 Subject: [PATCH 1/3] Make `int_format_into` API more flexible --- library/alloctests/tests/num.rs | 4 +++ library/core/src/fmt/num.rs | 60 ++++++++++++++++++++++++++------- 2 files changed, 51 insertions(+), 13 deletions(-) diff --git a/library/alloctests/tests/num.rs b/library/alloctests/tests/num.rs index 589b809009636..5a4b8439fa6a8 100644 --- a/library/alloctests/tests/num.rs +++ b/library/alloctests/tests/num.rs @@ -15,6 +15,10 @@ macro_rules! assert_nb { let mut buffer = NumBuffer::<$int>::new(); assert_eq!(value.format_into(&mut buffer), s.as_str()); + + // We check that bigger buffers can be used in `format_into`. + let mut buffer = NumBuffer::::new(); + assert_eq!(value.format_into(&mut buffer), s.as_str()); }; } diff --git a/library/core/src/fmt/num.rs b/library/core/src/fmt/num.rs index e1381ace44151..b4f341e084feb 100644 --- a/library/core/src/fmt/num.rs +++ b/library/core/src/fmt/num.rs @@ -1,6 +1,6 @@ //! Integer and floating-point number formatting -use crate::fmt::NumBuffer; +use crate::fmt::{NumBuffer, NumBufferTrait}; use crate::mem::MaybeUninit; use crate::num::fmt as numfmt; use crate::ops::{Div, Rem, Sub}; @@ -338,7 +338,7 @@ macro_rules! impl_Display { /// use core::fmt::NumBuffer; /// #[doc = concat!("let n = 0", stringify!($signed), ";")] - /// let mut buf = NumBuffer::new(); + #[doc = concat!("let mut buf = NumBuffer::<", stringify!($signed), ">::new();")] /// assert_eq!(n.format_into(&mut buf), "0"); /// #[doc = concat!("let n1 = 32", stringify!($signed), ";")] @@ -347,8 +347,23 @@ macro_rules! impl_Display { #[doc = concat!("let n2 = ", stringify!($signed::MAX), ";")] #[doc = concat!("assert_eq!(n2.format_into(&mut buf), ", stringify!($signed::MAX), ".to_string());")] /// ``` + /// + /// You can also use a [`NumBuffer`] used to store a bigger integer: + /// + /// ``` + /// #![feature(int_format_into)] + /// use core::fmt::NumBuffer; + /// + #[doc = concat!("let n = 32", stringify!($signed), ";")] + /// // We use a `NumBuffer` used to store a bigger integer. + /// let mut buf = NumBuffer::::new(); + /// assert_eq!(n.format_into(&mut buf), "32"); + /// ``` #[unstable(feature = "int_format_into", issue = "138215")] - pub fn format_into(self, buf: &mut NumBuffer) -> &str { + pub fn format_into(self, buf: &mut NumBuffer) -> &str { + const { + assert!(Self::BUF_SIZE <= T::BUF_SIZE, "buffer is not big enough"); + } let mut offset; #[cfg(not(feature = "optimize_for_size"))] @@ -381,7 +396,7 @@ macro_rules! impl_Display { /// use core::fmt::NumBuffer; /// #[doc = concat!("let n = 0", stringify!($unsigned), ";")] - /// let mut buf = NumBuffer::new(); + #[doc = concat!("let mut buf = NumBuffer::<", stringify!($unsigned), ">::new();")] /// assert_eq!(n.format_into(&mut buf), "0"); /// #[doc = concat!("let n1 = 32", stringify!($unsigned), ";")] @@ -390,8 +405,23 @@ macro_rules! impl_Display { #[doc = concat!("let n2 = ", stringify!($unsigned::MAX), ";")] #[doc = concat!("assert_eq!(n2.format_into(&mut buf), ", stringify!($unsigned::MAX), ".to_string());")] /// ``` + /// + /// You can also use a [`NumBuffer`] used to store a bigger integer: + /// + /// ``` + /// #![feature(int_format_into)] + /// use core::fmt::NumBuffer; + /// + #[doc = concat!("let n = 32", stringify!($unsigned), ";")] + /// // We use a `NumBuffer` used to store `u128`. + /// let mut buf = NumBuffer::::new(); + /// assert_eq!(n.format_into(&mut buf), "32"); + /// ``` #[unstable(feature = "int_format_into", issue = "138215")] - pub fn format_into(self, buf: &mut NumBuffer) -> &str { + pub fn format_into(self, buf: &mut NumBuffer) -> &str { + const { + assert!(Self::BUF_SIZE <= T::BUF_SIZE, "buffer is not big enough"); + } let offset; #[cfg(not(feature = "optimize_for_size"))] @@ -790,19 +820,20 @@ impl u128 { /// use core::fmt::NumBuffer; /// /// let n = 0u128; - /// let mut buf = NumBuffer::new(); + /// let mut buf = NumBuffer::::new(); /// assert_eq!(n.format_into(&mut buf), "0"); /// /// let n1 = 32u128; - /// let mut buf1 = NumBuffer::new(); - /// assert_eq!(n1.format_into(&mut buf1), "32"); + /// assert_eq!(n1.format_into(&mut buf), "32"); /// /// let n2 = u128::MAX; - /// let mut buf2 = NumBuffer::new(); - /// assert_eq!(n2.format_into(&mut buf2), u128::MAX.to_string()); + /// assert_eq!(n2.format_into(&mut buf), u128::MAX.to_string()); /// ``` #[unstable(feature = "int_format_into", issue = "138215")] - pub fn format_into(self, buf: &mut NumBuffer) -> &str { + pub fn format_into(self, buf: &mut NumBuffer) -> &str { + const { + assert!(Self::BUF_SIZE <= T::BUF_SIZE, "buffer is not big enough"); + } let diff = buf.capacity() - U128_MAX_DEC_N; // FIXME: Once const generics are better, use `NumberBufferTrait::BUF_SIZE` as generic const // for `fmt_u128_inner`. @@ -825,7 +856,7 @@ impl i128 { /// use core::fmt::NumBuffer; /// /// let n = 0i128; - /// let mut buf = NumBuffer::new(); + /// let mut buf = NumBuffer::::new(); /// assert_eq!(n.format_into(&mut buf), "0"); /// /// let n1 = i128::MIN; @@ -835,7 +866,10 @@ impl i128 { /// assert_eq!(n2.format_into(&mut buf), i128::MAX.to_string()); /// ``` #[unstable(feature = "int_format_into", issue = "138215")] - pub fn format_into(self, buf: &mut NumBuffer) -> &str { + pub fn format_into(self, buf: &mut NumBuffer) -> &str { + const { + assert!(Self::BUF_SIZE <= T::BUF_SIZE, "buffer is not big enough"); + } let diff = buf.capacity() - U128_MAX_DEC_N; // FIXME: Once const generics are better, use `NumberBufferTrait::BUF_SIZE` as generic const // for `fmt_u128_inner`. From a7a14d502c69c8866857cc99655f7ecb27ee93c6 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Tue, 8 Jul 2025 15:42:44 +0200 Subject: [PATCH 2/3] Reexport `core::NumBuffer` and `core::NumBufferTrait` items into `alloc` --- library/alloc/src/fmt.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/library/alloc/src/fmt.rs b/library/alloc/src/fmt.rs index 30f42050ac8ac..b728474f6435d 100644 --- a/library/alloc/src/fmt.rs +++ b/library/alloc/src/fmt.rs @@ -608,6 +608,8 @@ pub use core::fmt::{FromFn, from_fn}; pub use core::fmt::{LowerExp, UpperExp}; #[stable(feature = "rust1", since = "1.0.0")] pub use core::fmt::{LowerHex, Pointer, UpperHex}; +#[unstable(feature = "int_format_into", issue = "138215")] +pub use core::fmt::{NumBuffer, NumBufferTrait}; #[cfg(not(no_global_oom_handling))] use crate::string; From 82d9d62370580577f9e9dee0cba90a4e410475ff Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Tue, 8 Jul 2025 15:56:19 +0200 Subject: [PATCH 3/3] Add test for `NumBuffer` compilation error --- tests/ui/numeric/fmt.rs | 17 +++++++++++++++++ tests/ui/numeric/fmt.stderr | 22 ++++++++++++++++++++++ 2 files changed, 39 insertions(+) create mode 100644 tests/ui/numeric/fmt.rs create mode 100644 tests/ui/numeric/fmt.stderr diff --git a/tests/ui/numeric/fmt.rs b/tests/ui/numeric/fmt.rs new file mode 100644 index 0000000000000..be55e7e5dc869 --- /dev/null +++ b/tests/ui/numeric/fmt.rs @@ -0,0 +1,17 @@ +// Test to ensure that if you use a `NumBuffer` with a too small integer, it +// will fail at compilation time. + +//@ build-fail +//@ ignore-pass + +#![feature(int_format_into)] + +use std::fmt::NumBuffer; + +fn main() { + let x = 0u32; + let mut buf = NumBuffer::::new(); + x.format_into(&mut buf); +} + +//~? ERROR evaluation panicked diff --git a/tests/ui/numeric/fmt.stderr b/tests/ui/numeric/fmt.stderr new file mode 100644 index 0000000000000..fcd78ec9aa072 --- /dev/null +++ b/tests/ui/numeric/fmt.stderr @@ -0,0 +1,22 @@ +error[E0080]: evaluation panicked: buffer is not big enough + --> $SRC_DIR/core/src/fmt/num.rs:LL:COL + ::: $SRC_DIR/core/src/fmt/num.rs:LL:COL + | + = note: evaluation of `core::fmt::num::imp::::format_into::::{constant#0}` failed here + | + = note: this error originates in the macro `$crate::panic::panic_2021` which comes from the expansion of the macro `impl_Display` (in Nightly builds, run with -Z macro-backtrace for more info) + +note: erroneous constant encountered + --> $SRC_DIR/core/src/fmt/num.rs:LL:COL + | + = note: this note originates in the macro `impl_Display` (in Nightly builds, run with -Z macro-backtrace for more info) + +note: the above error was encountered while instantiating `fn core::fmt::num::imp::::format_into::` + --> $DIR/fmt.rs:14:5 + | +LL | x.format_into(&mut buf); + | ^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0080`.