Skip to content
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

Feature request: Add a way to capture a formatter that can be passed to format helper functions #74870

Open
3 tasks
LionsAd opened this issue Jul 28, 2020 · 4 comments
Labels
C-feature-request Category: A feature request, i.e: not implemented / a PR. T-libs-api Relevant to the library API team, which will review and decide on the PR/issue.

Comments

@LionsAd
Copy link

LionsAd commented Jul 28, 2020

Motivation

The Display trait allows lazy formatting of data. The formatter is passed in and used by the implemented fmt function for the struct. Often however applications and libraries want to expose helper functions to compose the display parts of a complex struct.

There are several ways to solve that:

  1. Return helper structs from each of those helper functions and implement display for each of them
  2. Use a buffer to write the data and pass in a Vec! (but loose all formatting parameters that way)
  3. Use internal functions within the fmt() function itself
  1. is not always feasible, 2) does use a wasteful extra buffer (which fmt avoids), 3) is possible when the helper functions should be private.

The motivation however here is that not only the Display::fmt function can be called by the user, but also the helper functions to format just parts of the struct (in our use-case different statistics).

The signature of the helper functions is the same as of fmt in the Display trait:

pub fn fmt_xyz(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
  writeln!(fmt, '{}', self.field_1);
}

But it is not possible to construct a formatter manually.

The only way to be able to call the helper function is to use:

The format crate or a helper Fmt() struct, which can capture the formatter passed in.

Proposed resolution

To solve that I am arguing that either a macro or a Fmt helper trait should be available in core rust so that there exists no function that you just can't call as a user (without an extra crate or helper trait).

The usage looks for example like this:

format!("{}", Fmt(|fmt| my_struct.fmt_xyz(fmt)));

The implementation of Fmt is as follows:

pub struct Fmt<F>(pub F) where F: Fn(&mut fmt::Formatter) -> fmt::Result;

impl<F> fmt::Debug for Fmt<F>
    where F: Fn(&mut fmt::Formatter) -> fmt::Result
{
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        (self.0)(f)
    }
}

(from: https://users.rust-lang.org/t/reusing-an-fmt-formatter/8531/3)

Discussion

I am not sure if Fmt is the right name as it feels a little bit weird.

Alternative proposals are like the format crate does it using a macro:

lazy_format!("{}", |fmt| my_struct.fmt_xyz(fmt));

Or what would be great if via some compiler magic a closure could directly work:

format!("{}", |fmt| my_struct.fmt_xyz(fmt));

From a user experience perspective the last version feels ideal, but I am not sure how difficult it would be to implement that.

Next steps

  • Discuss if it's possible to add this to rust stdlib
  • Discuss the name / implementation details
  • Create a PR

Related issues

Change scope

The scope is a small addition and hence seemed to not need a RFC per the guide lines.


If this has a chance of going in, I am happy to provide a PR.

@LionsAd LionsAd changed the title Feature request: Add a macro to capture a formatter that can be passed to format helper functions Feature request: Add a way to capture a formatter that can be passed to format helper functions Jul 28, 2020
@jonas-schievink jonas-schievink added C-feature-request Category: A feature request, i.e: not implemented / a PR. T-libs-api Relevant to the library API team, which will review and decide on the PR/issue. labels Jul 28, 2020
@tesuji
Copy link
Contributor

tesuji commented Jul 28, 2020

Can format_args! help your case?

@LionsAd
Copy link
Author

LionsAd commented Jul 29, 2020

No - format_args! won't work for that as the function needs to take the formatter as parameter.

@LionsAd
Copy link
Author

LionsAd commented Aug 17, 2020

I guess I should present this as a RFC in the forum instead?

@m-ou-se
Copy link
Member

m-ou-se commented Oct 19, 2023

I agree this would be useful. This would also be useful as an argument to functions like DebugStruct::field, which take something that is &dyn Debug or &dyn Display. In the standard library, we have many places where we implement a wrapper struct with its own Display/Debug impl just to pass it to such a function. The proposed type could help.

Or what would be great if via some compiler magic a closure could directly work:

format!("{}", |fmt| my_struct.fmt_xyz(fmt));

That is something worth investigating, but I think that'd come down to implementing Debug or Display for all FnOnce(Formatter) basically, which will cause issues in other places.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
C-feature-request Category: A feature request, i.e: not implemented / a PR. T-libs-api Relevant to the library API team, which will review and decide on the PR/issue.
Projects
None yet
Development

No branches or pull requests

4 participants