Skip to content

Implement int_format_into feature #142098

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 3 commits into
base: master
Choose a base branch
from

Conversation

GuillaumeGomez
Copy link
Member

@GuillaumeGomez GuillaumeGomez commented Jun 5, 2025

I took over #138338 with @madhav-madhusoodanan's approval.

Since #136264, a lot of changes happened so I made use of them to reduce the number of changes.

ACP approval: rust-lang/libs-team#546 (comment)

Associated Issue

r? @hanna-kruppe

@rustbot
Copy link
Collaborator

rustbot commented Jun 5, 2025

Failed to set assignee to hanna-kruppe: invalid assignee

Note: Only org members with at least the repository "read" role, users with write permissions, or people who have commented on the PR may be assigned.

@rustbot rustbot added S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. T-libs Relevant to the library team, which will review and decide on the PR/issue. labels Jun 5, 2025
assert_eq!(ret, value);

let mut buffer = NumBuffer::<$int>::new();
assert_eq!(value.format_into(&mut buffer), s.as_str());
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since format_into is not part of a trait, I needed to switch from a function to a macro to avoid the generics limitations.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You could write and implement a trait right here, in the test - right?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I could indeed, but would be better than the current code?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Less churn; other than that I don't have strong feelings.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If someone else agrees with you I'll make the change (lazyness++ 😆).

@GuillaumeGomez
Copy link
Member Author

r? @Amanieu

@rust-log-analyzer

This comment has been minimized.

@GuillaumeGomez GuillaumeGomez force-pushed the int_format_into branch 2 times, most recently from d11cb44 to 70ab4e0 Compare June 6, 2025 09:44
@rust-log-analyzer

This comment has been minimized.

@GuillaumeGomez GuillaumeGomez changed the title Int format into Implement int_format_into feature Jun 6, 2025
@GuillaumeGomez
Copy link
Member Author

Applied suggestions and opened another PR for the number of digits of u128 computation to not add even more changes to this PR.

@bors
Copy link
Collaborator

bors commented Jun 7, 2025

☔ The latest upstream changes (presumably #142133) made this pull request unmergeable. Please resolve the merge conflicts.

@GuillaumeGomez
Copy link
Member Author

Fixed merge conflict.

@GuillaumeGomez
Copy link
Member Author

Maybe you want to take a look at this one too @tgross35 ? :)

github-actions bot pushed a commit to Clownsw/miri that referenced this pull request Jun 21, 2025
…egers, r=tgross35

Use a distinct `ToString` implementation for `u128` and `i128`

Part of rust-lang/rust#135543.

Follow-up of rust-lang/rust#136264.

When working on rust-lang/rust#142098, I realized that `i128` and `u128` could also benefit from a distinct `ToString` implementation so here it.

The last commit is just me realizing that I forgot to add the format tests for `usize` and `isize`.

Here is the bench comparison:

| bench name | last nightly | with this PR | diff |
|-|-|-|-|
| bench_i128 | 29.25 ns/iter (+/- 0.66) | 17.52 ns/iter (+/- 0.7) | -40.1% |
| bench_u128 | 34.06 ns/iter (+/- 0.21) | 16.1 ns/iter (+/- 0.6) | -52.7% |

I used this code to test:

```rust
#![feature(test)]

extern crate test;

use test::{Bencher, black_box};

#[inline(always)]
fn convert_to_string<T: ToString>(n: T) -> String {
    n.to_string()
}

macro_rules! decl_benches {
    ($($name:ident: $ty:ident,)+) => {
        $(
	    #[bench]
            fn $name(c: &mut Bencher) {
                c.iter(|| convert_to_string(black_box({ let nb: $ty = 20; nb })));
            }
	)+
    }
}

decl_benches! {
    bench_u128: u128,
    bench_i128: i128,
}
```
/// Returns the length of the buffer.
#[unstable(feature = "int_format_into", issue = "138215")]
pub const fn len(&self) -> usize {
self.buf.len()
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This will always return 40, is this intended?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For now it's always 40 but I do hope in the future it will depend on the integer size when associated const support will be more advanced.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe return T::BUF_SIZE here for forward-compatiblity.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That would be problematic since we always rely on buf.len(). It would create a gap, so we cannot do that.

github-actions bot pushed a commit to rust-lang/rustc-dev-guide that referenced this pull request Jun 23, 2025
…egers, r=tgross35

Use a distinct `ToString` implementation for `u128` and `i128`

Part of rust-lang/rust#135543.

Follow-up of rust-lang/rust#136264.

When working on rust-lang/rust#142098, I realized that `i128` and `u128` could also benefit from a distinct `ToString` implementation so here it.

The last commit is just me realizing that I forgot to add the format tests for `usize` and `isize`.

Here is the bench comparison:

| bench name | last nightly | with this PR | diff |
|-|-|-|-|
| bench_i128 | 29.25 ns/iter (+/- 0.66) | 17.52 ns/iter (+/- 0.7) | -40.1% |
| bench_u128 | 34.06 ns/iter (+/- 0.21) | 16.1 ns/iter (+/- 0.6) | -52.7% |

I used this code to test:

```rust
#![feature(test)]

extern crate test;

use test::{Bencher, black_box};

#[inline(always)]
fn convert_to_string<T: ToString>(n: T) -> String {
    n.to_string()
}

macro_rules! decl_benches {
    ($($name:ident: $ty:ident,)+) => {
        $(
	    #[bench]
            fn $name(c: &mut Bencher) {
                c.iter(|| convert_to_string(black_box({ let nb: $ty = 20; nb })));
            }
	)+
    }
}

decl_benches! {
    bench_u128: u128,
    bench_i128: i128,
}
```
lnicola pushed a commit to lnicola/rust-analyzer that referenced this pull request Jun 23, 2025
…egers, r=tgross35

Use a distinct `ToString` implementation for `u128` and `i128`

Part of rust-lang/rust#135543.

Follow-up of rust-lang/rust#136264.

When working on rust-lang/rust#142098, I realized that `i128` and `u128` could also benefit from a distinct `ToString` implementation so here it.

The last commit is just me realizing that I forgot to add the format tests for `usize` and `isize`.

Here is the bench comparison:

| bench name | last nightly | with this PR | diff |
|-|-|-|-|
| bench_i128 | 29.25 ns/iter (+/- 0.66) | 17.52 ns/iter (+/- 0.7) | -40.1% |
| bench_u128 | 34.06 ns/iter (+/- 0.21) | 16.1 ns/iter (+/- 0.6) | -52.7% |

I used this code to test:

```rust
#![feature(test)]

extern crate test;

use test::{Bencher, black_box};

#[inline(always)]
fn convert_to_string<T: ToString>(n: T) -> String {
    n.to_string()
}

macro_rules! decl_benches {
    ($($name:ident: $ty:ident,)+) => {
        $(
	    #[bench]
            fn $name(c: &mut Bencher) {
                c.iter(|| convert_to_string(black_box({ let nb: $ty = 20; nb })));
            }
	)+
    }
}

decl_benches! {
    bench_u128: u128,
    bench_i128: i128,
}
```
@rust-lang rust-lang deleted a comment from rustbot Jun 28, 2025
@GuillaumeGomez
Copy link
Member Author

Thanks for the review @Amanieu! Applied all suggestions.

Also, gonna send a separate PR to use get_unchecked in this file because we could make things much better.

@rust-log-analyzer

This comment has been minimized.

@GuillaumeGomez
Copy link
Member Author

Safety annotation needs to be right on the unsafe block, not on the start of the expression. Well, noted.

@rust-log-analyzer

This comment has been minimized.

@GuillaumeGomez GuillaumeGomez force-pushed the int_format_into branch 3 times, most recently from a8b169e to 9e76d15 Compare July 1, 2025 09:44
@GuillaumeGomez
Copy link
Member Author

@Amanieu I went to the end of the usage of get_unchecked everywhere in #143277 and basically, there is absolutely no difference, the compiler is already optimizing all the code correctly.

@hanna-kruppe
Copy link
Contributor

Note that there were some recent PRs removing unsafe code from int Display impls that didn’t make a difference (#135265, #136594).

@GuillaumeGomez
Copy link
Member Author

GuillaumeGomez commented Jul 1, 2025

Yeah I will just revert the get_unchecked calls I added here as well. No point in keeping them.

@GuillaumeGomez
Copy link
Member Author

And done.

/// Initializes internal buffer.
#[unstable(feature = "int_format_into", issue = "138215")]
pub const fn new() -> Self {
// FIXME: Once const generics feature is working, use `T::BUF_SIZE` instead of 40.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you add a const { assert!(T::BUF_SIZE <= 40) } here.

/// Returns the length of the buffer.
#[unstable(feature = "int_format_into", issue = "138215")]
pub const fn len(&self) -> usize {
self.buf.len()
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe return T::BUF_SIZE here for forward-compatiblity.

@@ -248,6 +253,13 @@ macro_rules! impl_Display {
issue = "none"
)]
pub fn _fmt<'a>(self, buf: &'a mut [MaybeUninit::<u8>]) -> &'a str {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This needs to be an unsafe function because it makes assumptions on the size of buf.

n /= 10;

if n == 0 {
break;
}
}
}
cur
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should this be curr? How does this even compile?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh, that's because of optimize_for_size. I'm surprised it's not tested in CI.

@@ -336,20 +421,25 @@ macro_rules! impl_Display {
unsafe {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unsafe is not needed here since get_unchecked is not used.

@@ -598,12 +688,20 @@ impl u128 {
issue = "none"
)]
pub fn _fmt<'a>(self, buf: &'a mut [MaybeUninit<u8>]) -> &'a str {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same here, this needs to be unsafe because it assumes the slice size. Or _fmt_inner should be made safe.

tautschnig pushed a commit to model-checking/verify-rust-std that referenced this pull request Jul 3, 2025
…n-128-integers, r=tgross35

Use a distinct `ToString` implementation for `u128` and `i128`

Part of rust-lang#135543.

Follow-up of rust-lang#136264.

When working on rust-lang#142098, I realized that `i128` and `u128` could also benefit from a distinct `ToString` implementation so here it.

The last commit is just me realizing that I forgot to add the format tests for `usize` and `isize`.

Here is the bench comparison:

| bench name | last nightly | with this PR | diff |
|-|-|-|-|
| bench_i128 | 29.25 ns/iter (+/- 0.66) | 17.52 ns/iter (+/- 0.7) | -40.1% |
| bench_u128 | 34.06 ns/iter (+/- 0.21) | 16.1 ns/iter (+/- 0.6) | -52.7% |

I used this code to test:

```rust
#![feature(test)]

extern crate test;

use test::{Bencher, black_box};

#[inline(always)]
fn convert_to_string<T: ToString>(n: T) -> String {
    n.to_string()
}

macro_rules! decl_benches {
    ($($name:ident: $ty:ident,)+) => {
        $(
	    #[bench]
            fn $name(c: &mut Bencher) {
                c.iter(|| convert_to_string(black_box({ let nb: $ty = 20; nb })));
            }
	)+
    }
}

decl_benches! {
    bench_u128: u128,
    bench_i128: i128,
}
```
@GuillaumeGomez
Copy link
Member Author

Applied suggestions.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. T-libs Relevant to the library team, which will review and decide on the PR/issue.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

10 participants