rust-lang / rust

Empowering everyone to build reliable and efficient software.
https://www.rust-lang.org
Other
96.75k stars 12.5k forks source link

Tracking Issue for `debug_closure_helpers` #117729

Open jmillikin opened 10 months ago

jmillikin commented 10 months ago

Feature gate: #![feature(debug_closure_helpers)]

This is a tracking issue for adding helpers to core::fmt that can use closures for formatting values.

ACP: https://github.com/rust-lang/libs-team/issues/288

Public API

// core::fmt

impl DebugList<'_, '_> {
    fn entry_with<F>(&mut self, entry_fmt: F) -> &mut Self
    where
        F: FnOnce(&mut Formatter) -> fmt::Result;
}

impl DebugMap<'_, '_> {
    fn key_with<F>(&mut self, key_fmt: F) -> &mut Self
    where
        F: FnOnce(&mut Formatter) -> fmt::Result;

    fn value_with<F>(&mut self, value_fmt: F) -> &mut Self
    where
        F: FnOnce(&mut Formatter) -> fmt::Result;
}

impl DebugSet<'_, '_> {
    fn entry_with<F>(&mut self, entry_fmt: F) -> &mut Self
    where
        F: FnOnce(&mut Formatter) -> fmt::Result;
}

impl DebugStruct<'_, '_> {
    fn field_with<F>(&mut self, name: &str, field_fmt: F) -> &mut Self
    where
        F: FnOnce(&mut Formatter) -> fmt::Result;
}

impl DebugTuple<'_, '_> {  // also DebugSet
    fn field_with<F>(&mut self, field_fmt: F) -> &mut Self
    where
        F: FnOnce(&mut Formatter) -> fmt::Result;
}

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

impl<F> Debug for FormatterFn<F>
where
    F: Fn(&mut Formatter) -> fmt::Result;

impl<F> Display for FormatterFn<F>
where
    F: Fn(&mut Formatter) -> fmt::Result;

Steps / History

Unresolved Questions

QuineDot commented 9 months ago

Taking inspiration from iter::from_fn, I suggest a module level helper function:

core::fmt::from_fn<F>(f: F) -> FormatterFn<F>
where
    F: Fn(&mut Formatter<'_>) -> Result
{
    FormatterFn(f)
}

Plus perhaps also


Is there any particular reason it doesn't implement Binary, LowerExp, etc? (Why both Debug and Display but not all formats?)

steffahn commented 6 months ago

Is there any particular reason it doesn't implement Binary, LowerExp, etc? (Why both Debug and Display but not all formats?)

With “just” Debug and Display it would kind-of follow the precedent of fmt::Arguments<'_>.

workingjubilee commented 4 months ago

these are really nice btw. I think QuineDot's suggestion could be a cool refactoring of this, but it's very nice to be able to basically randomly throw in a simple closure that provides debug formatting, without having to roll the internals yourself, since it's just... like, the case you're most likely doing this, you're already implementing some kind of explicit Debug or "Debug adapter" and you don't wanna have to do another one for every custom field.

workingjubilee commented 4 months ago

QuineDot's suggestion is in fact very close to one of the listed alternatives in the original idea! The main difference is the use of a free higher-order function instead of a constructor, which might be better for type inference reasons.

01mf02 commented 2 months ago

I would love to see just fmt::from_fn stabilised, as suggested by @QuineDot. The symmetry with iter::from_fn is apparent, and this seems relatively uncontroversial. What is the status of stabilising this?

workingjubilee commented 2 months ago

someone would need to PR fmt::from_fn, to start.

SUPERCILEX commented 1 month ago

Is there anything remaining for stabilization? These are super useful.

its-the-shrimp commented 1 month ago

The change suggested above has just been merged into master, the description of the issue should be changed to reflect the new API

01mf02 commented 1 month ago

Thanks for your work, @its-the-shrimp!