Any way to override Debug output recursively?

I wonder if there is possible to override some type Debug output without introducing any newtypes or dealing with struct structure in any way. For example

struct Foo {
  a: [u8; 32],
  b: [u8; 32],
  c: [u8; 32],
}

I'd like to get debug output like:

foo = Foo {
  a: "0x06df3b2bbb68adc8b0e302443692037ed9f91b42000000000000000000000063",
  b: "0xffaf3b2bbb68adc8b0e302443692037ed9f91b42000000000000000000000063",
  c: "0xbbcc3b2bbb68adc8b0e302443692037ed9f91b42000000000000000000000063",
}

instead of default output Foo { a: [0, 10, 26, ...], ... }

It's easy feasible with wrapping everything in some HexArrayPrinter but I wonder if there is any way to solve this without pollution the codebase with .0 everywhere. I happened to make it work in serialization via serde_as which allows you to specify custom serialization via attributes - I wonder if there is something similar for the task.

You can write the Debug impl yourself and put the HexArrayPrinter there:

impl std::fmt::Debug for Foo {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        // destructuring will make it fail to compile 
        // if you later add a field and forget to update here
        let Foo { a, b, c } = self;
        struct HexArray<'a>(&'a [u8]);
        // impl Debug for HexArray here
        f.debug_struct("Foo")
            .field("a", &HexArray(a))
            .field("b", &HexArray(b))
            .field("c", &HexArray(c))
            .finish()
    }
}

To answer the question, no you can't override a trait implementation.

7 Likes

This sounds unfortunate. I'd really like to have it generated somehow

You could use the crate derive_more. Its Display macro seems able to do something like that (provided you still define the HexArrayPrinter wrapper, and it's no longer the Debug trait, it's Display).

Though in my opinion, that's a hard to justify dependency. The code here is simple enough.

2 Likes

You can always wrap the fields, but I think it's unnecessary.