Small proposal: add DebugStruct::non_exhaustive

So at the moment, you can do something like

struct Opaque {
    inner1: u32,
    inner2: OpaqueObject
}

impl Debug for Opaque {
    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
        f.debug_struct("Opaque")
            .field("inner1", self.inner1)
            .finish();
    }
}

and get e.g.

Opaque { inner1: 8 }

but this does not tell the reader that there are other fields on Opaque.

It would be possible to show this with a new method non_exhaustive function on that you would use like

impl Debug for Opaque {
    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
        f.debug_struct("Opaque")
            .field("inner1", self.inner1)
            .non_exhaustive()
            .finish();
    }
}

which would output

Opaque { inner1: 8, .. }

thereby telling the reader that there are more fields that are not representable.

We could also add a method like opaque_field that would look like

impl Debug for Opaque {
    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
        f.debug_struct("Opaque")
            .field("inner1", self.inner1)
            .opaque_field("inner2")
            .finish();
    }
}

and output

Opaque { field1: 8, field2: <opaque> }

where the string <opaque> is bikesheddable (e.g. ..).

9 Likes

Note that opaque fields can be accomplished with e.g.

struct ImplDebug<'a>(&'a str);
impl fmt::Debug for ImplDebug<'_> {
    fn fmt(&self, f: fmt::Formatter<'_>) -> fmt::Result {
        f.write_str(self.0)
    }
}

.field("inner2", &ImplDebug("_"))

That's not to say the opaque helper shouldn't be added, though; providing the method is a good way to make it more obvious.

The non_exhaustive method makes a lot of sense and definitely should be added! Perhaps #[derive(Debug)] should even use it for #[non_exhaustive] structures.

This is a small change and can just be a PR.

1 Like

Even easier with

.field("inner2", &format_args!("_"))

:wink:

2 Likes

I did a PR.

2 Likes