There are many times when I find it cumbersome to work with fmt::Debug especially, when I want to use the debug_* family of helpers with multi-level output. Currently this involves creating a data structure to wrap part of my struct, implementing fmt::Debug for it, then referring to it in e.g. my DebugStruct::field method call. An example:
// TextLayout is an opaque struct in another crate with a `size`
// method, that does not implement `Debug`.
struct Layout {
inner: TextLayout,
}
impl Debug for Layouts {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
struct DebugLayout<'a>(&'a TextLayout);
impl Debug for Layouts {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.debug_struct("TextLayout")
.field("size", &self.0.size())
.finish()
}
}
f.debug_struct("Layout")
.field("inner", &DebugLayout(&self.inner))
.finish()
}
}
I feel like it would be easier if there was something like
impl<F> fmt::Display for F where F: Fn(&mut fmt::Formatter) -> fmt::Result {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
(self)(f)
}
}
Note that you can define a general solution yourself, e.g.
// TextLayout is an opaque struct in another crate with a `size`
// method, that does not implement `Debug`.
struct Layout {
inner: TextLayout,
}
impl fmt::Debug for Layout {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("Layout")
.field(
"inner",
&DebugFn(|f| {
f.debug_struct("TextLayout")
.field("size", &self.inner.size())
.finish()
}),
)
.finish()
}
}
// generally usable abstraction
pub struct DebugFn<F>(pub F)
where
F: Fn(&mut fmt::Formatter<'_>) -> fmt::Result;
impl<F> fmt::Debug for DebugFn<F>
where
F: Fn(&mut fmt::Formatter<'_>) -> fmt::Result,
{
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
self.0(f)
}
}
I also think that – if anything – the standard library should provide such a wrapper type (or alternatively a function creating it), and not create a general implementation for the closures/functions themself!
Good point. For now, that’s also possible to achieve through an extension crate without needing to change the standard library (yet, the API might be useful enough for eventually being included there as-well).