How should I be separating User Display formatting from System formatting in custom structs?

playground example: Rust Playground

If I want different formats for Human Readable vs System Readable what's the recommended way of doing this?

I was assuming since println!("{}") uses fmt::Display that this should be using human readable format, but I've been strongly discouraged from manually implementing .to_string() which I would expect to be system readable.

Should I be using .pretty() for human readable? Is there a consensus on the idiomatic way to do this?

Clarification: I was expecting something like this, but I've been discouraged from implementing .to_string() myself

.pretty() => impl std::fmt::Display
.value()  => .to_string()  // manually implementing this is discouraged
.debug()  => impl std::fmt::Debug

the TL:DR if someone else comes here with the same request I recommend this for converting to a common data interchange format

extern crate serde;        // Serde is a framework for serializing and deserializing Rust data structures efficiently and generically.
extern crate serde_derive; // and for full customization: https://serde.rs/custom-serialization.html

Isn't that what the Debug trait would be for?

I assume Debug would be for troubleshooting, not display formatting for end users of the program?

Er, yeah, Display would be for end users, Debug for system formatting, as you call it. Or am I misunderstanding you?

by "system formatting" I mean the expected output if passing to another computer system (like in this example if wanted to send to a dialer API), but I wanted to make the struct generalized for public use

this is in contrast to a more verbose debugging output I'd want when troubleshooting

Oh ok, yeah, so how about the alternate formatter that would output a still-human-consumable, but condensed format to send along?

Otoh if you're thinking of exchanging data between "systems", you might want to look into serialization, like json or so.

You have the right sort of application in mind.

I wasn't sure if there was a convention for how to represent the format intended for Humans and the format you'd expect to send to a serializer (if the formats are different)

I guess I was expecting a .display(), .value(), and .debug() formatting convention. I would expect {} for the display and {:?} for the debug, but I didn't know if there was some idiomatic way to implement the .value() part. I expected it to be .to_string() (or whatever the closest native type is) but I've been strongly discouraged from implementing that function myself.

I basically know nothing about serialization, but as far as I understood it, you'd directly give your struct to the serializer and it constructs the correct string for you, no need to do a different format for it.

I would expect it to digest well known types like String, but not custom structs, so my impluse would be to pass it as phone_number.to_string(), but like I said it seems you're expected to let that auto-derive from ::Display. Which while that works fine as a default, if the .pretty() and .to_string() formats are the same; if they should be different this seems problematic because you can't separate them.

This seems like a not uncommon thing to encounter so I was hoping there might be a convention in place I just haven't discovered yet since I'm new here

I've implemented that for you, just to show you that it can work on your struct: Rust Playground (unless I'm misunderstanding you, I kinda feel like that's the case).

That's basically what I was looking for. I thought there was an innate common approach but it looks like serde is a generic serializer with over 10,000 downloads in the last 90 days so that works as a convention.

If someone else comes here with the same request I recommend this

extern crate serde;        // Serde is a framework for serializing and deserializing Rust data structures efficiently and generically.
extern crate serde_derive; // and for full customization: https://serde.rs/custom-serialization.html

Yeah, generally the rust stdlib is pretty thin, and you should not be afraid to use 3rd party crates. Serde is very well known in the community and generally praised. Did you know the rust cookbook? It contains a lot of those "commonly known" things.

so that works as a convention.

Actually serde is so well-known that when you use a struct from a 3rd party crate, you can sort-of-expect it to implement Serialize, or have a good chance it will be added if you open an issue for that.

1 Like

I hadn't, I'll check it out. I'm still going through book second edition (chapter 12 currently)