-
Notifications
You must be signed in to change notification settings - Fork 123
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
FR: Add #[display(delegate)]
option for newtypes which delegates to wrapped type
#321
Comments
#[display(forward)]
option for newtypes which delegates to wrapped type#[display(delegate)]
option for newtypes which delegates to wrapped type
Using no attribute at should already do what you want: #[derive(derive_more::Display)]
struct Num(usize); |
So it does, thanks. For some reason I was convinced that |
@mina86 what is the problem to just use other traits directly? #[derive(derive_more::Display)]
#[display("{:?}", _0.display())]
struct Path(std::path::Path, ()); |
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
} |
@mina86 hmmm... good catch! 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:?}")
}
} Do you see any pitfalls with this? |
That would work for me and I don’t see any issues. Just two points to #[derive(derive_more::Display)]
#[display("{_0:x}")] // delegates to LowerHex?
struct Num(usize);
#[derive(derive_more::Display)]
#[display("{}", _0.display())] // does _0.display().fmt(fmtr)?
struct Path(std::path::PathBuf); |
I think that's quite interesting. The only downside I can see (apart from the extra code) that it if you try to strip them intentionally, there's no way to do that. But that doesn't seem a huge problem. That does make it a breaking change though, so we'd want to do this for the 1.0 release... |
I actually think we should support it even with a prefix/suffix. So if you have this: #[derive(derive_more::Display)]
#[display("prefix-{_0:?}-suffix")] // <--- it's clear to be a trivial delegation case
struct Num(usize); it generates: impl std::fmt::Display for Num {
fn fmt(&self, fmtr: &mut std::fmt::Formatter) -> std::fmt::Result {
let _0 = &self.0;
fmt.write_str("prefix-")
std::fmt::Debug::fmt(_0, fmtr)
fmt.write_str("-suffix")
}
} |
I’m not sure about the latter point. Consider in your example, it’s |
There is always a way to do that like this: #[derive(Display)]
#[display("{}", format_args!("{_0:?}"))]
struct Num(usize);
I don't think so. It's clearly not a delegation case anymore, and following I think we should add this only if somebody will ask for it for real. Otherwise, seems to be unnecessary complication.
|
alright I'm convinced. Let's only handle the trivial delegation cases. |
## Synopsis See #321 (comment): > You’re discarding formatting flags provided by the user in format string, e.g.: > > ```rust > #[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 #321 (comment): > 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). > > ```rust > #[derive(derive_more::Display)] > #[display("{_0:?}")] // <--- it's clear to be a trivial delegation case > struct Num(usize); > ``` > > would expand to > > ```rust > 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 > > ```rust > impl std::fmt::Display for Num { > fn fmt(&self, fmtr: &mut std::fmt::Formatter) -> std::fmt::Result { > let _0 = &self.0; > write!(fmtr, "{_0:?}") > } > } > ```
## Synopsis See JelteF/derive_more#321 (comment): > You’re discarding formatting flags provided by the user in format string, e.g.: > > ```rust > #[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 JelteF/derive_more#321 (comment): > 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). > > ```rust > #[derive(derive_more::Display)] > #[display("{_0:?}")] // <--- it's clear to be a trivial delegation case > struct Num(usize); > ``` > > would expand to > > ```rust > 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 > > ```rust > impl std::fmt::Display for Num { > fn fmt(&self, fmtr: &mut std::fmt::Formatter) -> std::fmt::Result { > let _0 = &self.0; > write!(fmtr, "{_0:?}") > } > } > ```
Add option to allow delegating Display implementation to wrapped field or to implementation of another formatting trait.
Currently, using something akin to
#[display(fmt = "{}", _0)]
for newtypes suffers from the issues of all user-provided flags being reset. For example:The idea is to support
#[dispaly(delegate)]
annotation which would delegate call rather than usewrite!
macro. For example:would generate:
This could be further extended to full form:
which would end up as:
Those are further ideas though. Even just a simple
#[display(delegate)]
which would work on structs with a single field would be neat.The text was updated successfully, but these errors were encountered: