Implementing LowerHex to preserve format options

Viewed 55

Let's say I have a type Point whose coordinates I want to format in hex. I can do this:

use std::fmt;

struct Point {
    x : i32,
    y : i32
}

impl fmt::LowerHex for Point {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        write!(f, "(x=")?;
        fmt::LowerHex::fmt(&self.x, f)?;
        write!(f, ", y=")?;
        fmt::LowerHex::fmt(&self.y, f)?;
        write!(f, ")")
    }
}

fn main() {
    let p = Point { x : 100, y : 200 };
    println!("Point is {0:x} or {0:#06x}", p);
}

That prints, as desired:

Point is (x=64, y=c8) or (x=0x0064, y=0x00c8)

Is this the best way of implementing LowerHex for Point?

And, if I want to them implement UpperHex as well, do I just have to basically duplicate all of this logic again?

1 Answers

Despite the lack of derive macros for LowerHex and UpperHex, there is a formatting string that automatically applies hexadecimal printing to the struct's members as long as the struct implements Debug. Placing a question mark after the "hexadecimal x" means that the object should be debug-printed, but its integer members should be printed in hexadecimal.

Then, if you manually implement Debug to get the basic format that you want, using the provided fmt::Formatter to write the object's fields, things will "just work".

use std::fmt;

struct Point {
    x: i32,
    y: i32,
}

impl fmt::Debug for Point {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        f.write_str("(x=")?;
        self.x.fmt(f)?;
        f.write_str(", y=")?;
        self.y.fmt(f)?;
        f.write_str(")")?;

        Ok(())
    }
}

fn main() {
    let p = Point { x: 100, y: 200 };
    println!("{:?}", p);
    println!("{:x?}", p);
    println!("{:#06x?}", p);
    println!("{:#06X?}", p);
}

This prints the desired

(x=100, y=200)
(x=64, y=c8)
(x=0x0064, y=0x00c8)
(x=0x0064, y=0x00C8)
Related