JelteF / derive_more

Some more derive(Trait) options
MIT License
1.73k stars 123 forks source link

Delegation for `fmt` traits (#321) #322

Closed tyranron closed 10 months ago

tyranron commented 10 months ago

Resolves #321

Synopsis

See https://github.com/JelteF/derive_more/issues/321#issuecomment-1854069597:

You’re discarding formatting flags provided by the user in format string, e.g.:

#[derive(derive_more::Display)]
#[display(fmt = "{:?}", _0)]
struct Num(usize);

impl std::fmt::Debug for Num {
    fn fmt(&self, fmtr: &mut std::fmt::Formatter) -> std::fmt::Result {
        self.0.fmt(fmtr)
    }
}

fn main() {
    let num = Num(7);
    println!("{num:03?}");  // prints ‘007’ as expected
    println!("{num:03}");   // prints ‘7’ instead
}

Solution

See https://github.com/JelteF/derive_more/issues/321#issuecomment-1854382465:

Theoretically, we can support this with the current syntax, because we can detect so-called trivial cases and transform them into delegation (we do parse formatting string literal anyway).

#[derive(derive_more::Display)]
#[display("{_0:?}")] // <--- it's clear to be a trivial delegation case
struct Num(usize);

would expand to

impl std::fmt::Display for Num {
    fn fmt(&self, fmtr: &mut std::fmt::Formatter) -> std::fmt::Result {
        let _0 = &self.0;
        std::fmt::Debug::fmt(_0, fmtr)
    }
}

rather than

impl std::fmt::Display for Num {
    fn fmt(&self, fmtr: &mut std::fmt::Formatter) -> std::fmt::Result {
        let _0 = &self.0;
        write!(fmtr, "{_0:?}")
    }
}

Checklist