I wrote up what follows and then looked to see if anything had changed. And it has! This ACP-accepted proposal would fix a lot of things. (Last I looked, making fill
dynamic was the only thing I found, IIRC.)
Sometimes I support the format spec inputs the best I can, but it's a pain. I don't think the system is the most well designed or intuitive thing. Here's how you read the format specification as an implementor...
Format Spec Input |
fmt::Formatter<'_> method |
Notes |
Fill |
fill -> char |
Static (!) |
Alignment |
align -> Option<Alignment> |
Static |
Sign |
sign_minus -> bool , sign_plus -> bool |
Static |
Alternative |
alternate -> bool |
Static |
Zero |
sign_aware_zero_pad -> bool |
Static |
Width |
width -> Option<usize> |
Dynamic |
Precision |
precision -> Option<usize> |
Dynamic |
Debug Hex Case |
debug_lower_hex -> bool , debug_upper_hex -> bool |
Private methods! |
First of all, the only way to adjust these is to create a new Formatter<'_>
by using some format-str taking macro. If you just pass the &mut fmt::Formatter<'_>
on to your sub-fields, you're passing along all the spec inputs as well.
Second of all, by "Static" in the last column, I mean the value of the spec input has to be in your (literal) format-str; it can't be a dynamic parameter. So if you want to, say, adjust the width and pass on other things like Alternate, you have to do something like...
// (Ignoring `align` and `sign_aware_zero_pad` for this example)
match (f.sign_minus(), f.sign_plus(), f.alternate()) {
(false, false, false) => write!(f, "{:width$}", field, width=...)?,
(false, false, true ) => write!(f, "{:#width$}", field, width=...)?,
// ...
And you simply cannot reasonably preserve the fill using the formatting system (for more than a handful of expected and hard-coded values, anyway).
It'd be nicer if you could...
impl<'a> Formatter<'a> {
fn set_fill(&mut self, fill: char) { /* ... */ }
fn set_alignment(&mut self, alignment: Option<Alignment>) { /* ... */ }
// ...
// And perhaps even
/// Reborrow this `Formatter`. The reborrowed `Formatter` has
/// it's own copy of the input parameters, which can be modified
/// independently of the original `Formatter`.
fn borrow(&mut self) -> Formatter<'_> { /* ... */ }
(Third of all, there should be a sign -> Option<Sign>
or such, not a method for each of -
and +
. Although flags
is deprecated, it still shines through.)
((Fourth of all, you have to jump through hoops to use the struct helpers in a Display
implementation, since they're bound on T: Debug
.))