Skip to content

Commit df1d9e1

Browse files
sueun-devrobjtede
authored andcommitted
fix: honor precision when a width is set in ByteSize Display
With a width, the Display impl used f.pad(display.to_string()). That renders at the default precision and then f.pad treats the precision as a maximum width, so a value like ByteSize::mib(1908) formatted with {:>12.5} came out as " 1.9 G" - the precision ignored and the unit truncated. Render with the requested precision first, then apply only the width, fill, and alignment.
1 parent 2d184f8 commit df1d9e1

1 file changed

Lines changed: 47 additions & 1 deletion

File tree

src/lib.rs

Lines changed: 47 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -361,7 +361,40 @@ impl fmt::Display for ByteSize {
361361
// allocation-free fast path for when no formatting options are specified
362362
fmt::Display::fmt(&display, f)
363363
} else {
364-
f.pad(&display.to_string())
364+
// `display.to_string()` renders at the default precision, and `f.pad`
365+
// reinterprets the formatter's precision as a *maximum* width. Together
366+
// they drop the requested precision and truncate the value mid-unit
367+
// (e.g. `{:>12.5}` rendered "1.86328 GiB" as "1.9 G"). Render with the
368+
// requested precision first, then apply only the width, fill, and align.
369+
let content = match f.precision() {
370+
Some(precision) => alloc::format!("{display:.precision$}"),
371+
None => display.to_string(),
372+
};
373+
374+
let padding = f
375+
.width()
376+
.unwrap_or(0)
377+
.saturating_sub(content.chars().count());
378+
if padding == 0 {
379+
return f.write_str(&content);
380+
}
381+
382+
let (left, right) = match f.align() {
383+
Some(fmt::Alignment::Right) => (padding, 0),
384+
Some(fmt::Alignment::Center) => (padding / 2, padding - padding / 2),
385+
Some(fmt::Alignment::Left) | None => (0, padding),
386+
};
387+
388+
let mut buf = [0u8; 4];
389+
let fill = f.fill().encode_utf8(&mut buf);
390+
for _ in 0..left {
391+
f.write_str(fill)?;
392+
}
393+
f.write_str(&content)?;
394+
for _ in 0..right {
395+
f.write_str(fill)?;
396+
}
397+
Ok(())
365398
}
366399
}
367400
}
@@ -665,4 +698,17 @@ mod alloc_tests {
665698
assert_eq!("|357 B-----|", format!("|{:-<10}|", ByteSize(357)));
666699
assert_eq!("|--357 B---|", format!("|{:-^10}|", ByteSize(357)));
667700
}
701+
#[test]
702+
fn test_display_width_with_precision() {
703+
let size = ByteSize::mib(1908);
704+
// Precision is honored as decimal places even when a width is given, and
705+
// the rendered value is never truncated to satisfy the precision.
706+
assert_eq!("| 1.86328 GiB|", format!("|{size:>12.5}|"));
707+
assert_eq!("|1.86328 GiB |", format!("|{size:<12.5}|"));
708+
assert_eq!("|1.86328 GiB |", format!("|{size:12.5}|"));
709+
assert_eq!("|--1.86328 GiB--|", format!("|{size:-^15.5}|"));
710+
assert_eq!("| 2 GiB|", format!("|{size:>10.0}|"));
711+
// Width narrower than the value leaves it intact instead of truncating.
712+
assert_eq!("1.86328 GiB", format!("{size:3.5}"));
713+
}
668714
}

0 commit comments

Comments
 (0)