1

I'm implementing a file format parser, and I have an enum which reflects the general chunks allowed in the file specification. Something like:

#[derive(Debug)]
pub enum FileChunk {
    FileVersionChunk { major: u16, minor: u16 },
    AuthorChunk { name: String },

    // many many more variants following the specs...

    DataChunk { data: Vec<u8> },
}

For debugging purposes I want to implement the Debug trait for this enum. The standard implementation #[derive(Debug)] is super useful for that purpose, but has one issue: Some variants like the DataChunk contain huge data elements, which I want to abbreviate in the debugging output. How can this be accomplished?


I'm new to Rust -- naively I would see two approaches:

  • Keep the default #[derive(Debug)] implementation but somehow override that a certain variant should have a special implementation. I couldn't figure out though, if something like that is possible in Rust.
  • Remove the default #[derive(Debug)] implementation, and implement the trait explicitly. In this case I'm trying to find a solution that allows to only implement the specific variant DataChunk manually, but somehow fall back to a default implementation for all other cases1. However I can't figure out how to make such a fallback work. I tried the following as a test, but that leads to an infinite recursion, because the write! expression basically calls fmt again.
impl Debug for FileChunk {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::result::Result<(), std::fmt::Error> {
        write!(f, "{:#?}", self)
    }
}

1 the specs require ~30 variants, so manually implementing all of them would be very tedious, and there are further enums where I have the same problem.

bluenote10
  • 23,414
  • 14
  • 122
  • 178
  • 2
    [Here's a way to apply Mithnar's answer to your problem.](https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=66e7287e9821481775cb96fcbfb82e3a) – trent Nov 08 '19 at 12:21
  • `Formatter` is not really related to the whole `derive` thing. Deriving traits is implemented in Rust with [procedural macros](https://doc.rust-lang.org/reference/procedural-macros.html#derive-macros)... I'm not sure exactly where the code is for `derive(Debug)`, but that's probably not what you want because it's a lot more work than just implementing it manually, given you only have one struct to worry about. – trent Nov 08 '19 at 12:28
  • Other related questions might be: [Can traits be used on enum types?](https://stackoverflow.com/q/51567350/3650362), [How do I implement a trait for an enum and its respective variants?](https://stackoverflow.com/q/57066471/3650362), and [Is there a way to use existing structs as enum variants?](https://stackoverflow.com/q/49705007/3650362) – trent Nov 08 '19 at 12:33
  • [Apparently `derive(Debug)` is still built in to the compiler, despite proc macros being stable now.](https://github.com/rust-lang/rust/blob/master/src/libcore/fmt/mod.rs#L556) – trent Nov 08 '19 at 12:37
  • How does the new type pattern relate to this example? Feel free to convert your comment into an answer. I failed to see the immediate connection to the other question, so a concrete answer would still help newcomers. – bluenote10 Nov 08 '19 at 12:37
  • I did create a newtype, but you might have overlooked it because it has the same name as the variant (`DataChunk`). – trent Nov 08 '19 at 12:40
  • Now I get it. I basically need another layer of nesting. Not so nice that I have an unnecessary nesting just for getting my debug output right though :-/. – bluenote10 Nov 08 '19 at 12:51
  • Depends on your definition of "necessary", I guess :-) The way I see it, one of your variants is "`Vec`, but with a different `Debug` behavior", which is semantically a different type than just "`Vec`". But I can see how it might be useful to have a more flexible `Debug` macro. [(There are other reasons why `derive`ing doesn't always give the right answer that I'd like to see addressed.)](https://github.com/rust-lang/rust/issues/26925) – trent Nov 08 '19 at 12:59

0 Answers0