fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
match from_utf8(&self.data) { //Some u8 array
Ok(str) => { f.write_str(str) }
Err(err) => {
// We have junk in this array which is not a valid UTF-8
// What should I do with 'err' here?
Err(std::fmt::Error::default())
}
}
}
I wish I could return Utf8Error somehow, so println!("{foo:?}") would panic telling client what happened.
However, docs say
/// This type does not support transmission of an error other than that an error
/// occurred. Any extra information must be arranged to be transmitted through
/// some other means.
That means, I can't attach Utf8Error forcing caller to guess why did my struct failed to print debug info.
Why doesn't fmt::Error have reason field?
What is the right thing to do here?
I am aware of from_utf8_lossy and other things, so I could return junk in case of error, but I want to emphasize that I failed to convert array to string.
Or do I misunderstand the idea of fmt? Maybe it should never fail, and error is here only for cases like broken formatter (i.e trying to print to the closed descriptor etc)?
Yes. The purpose of fmt::Error existing at all is to allow a formatting operation to be cancelled midway by its fmt::Write destination, such as on an IO error. The fmt implementations themselves are supposed to be infallible. This is unfortunately not very prominently documented; it's only mentioned in the fmt module documentation:
However, they should never return errors spuriously. That is, a formatting implementation must and may only return an error if the passed-in Formatter returns an error. This is because, contrary to what the function signature might suggest, string formatting is an infallible operation. This function only returns a result because writing to the underlying stream might fail and it must provide a way to propagate the fact that an error has occurred back up the stack.
What to do instead?
For fmt::Debug in particular, you might prefer to err on the side of printing no matter what, and use from_utf8_lossy or similar, or even an explicit printed “I'm broken” report — for more use in debugging.
But for fmt::Display or other "actual output of your program" formatting, if you encounter a bug such as a broken invariant in your own data type (if the bytes should always be UTF-8 and if they aren't, a constructor failed to do its job of checking), then just panic!("...") for that.
If there is some condition where your type might or might not be printable, then check the condition before producing a Display implementation.