Skip to content

Commit fb06af3

Browse files
committed
df: add tracing zero for single digits
1 parent 68a0369 commit fb06af3

File tree

2 files changed

+143
-51
lines changed

2 files changed

+143
-51
lines changed

src/uu/df/src/blocks.rs

Lines changed: 115 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,13 @@ impl SuffixType {
7777
/// Convert a number into a magnitude and a multi-byte unit suffix.
7878
///
7979
/// The returned string has a maximum length of 5 chars, for example: "1.1kB", "999kB", "1MB".
80-
pub(crate) fn to_magnitude_and_suffix(n: u128, suffix_type: SuffixType) -> String {
80+
/// `add_tracing_zero` allows to add tracing zero for values in 0 < x <= 9
81+
///
82+
pub(crate) fn to_magnitude_and_suffix(
83+
n: u128,
84+
suffix_type: SuffixType,
85+
add_tracing_zero: bool,
86+
) -> String {
8187
let bases = suffix_type.bases();
8288
let suffixes = suffix_type.suffixes();
8389
let mut i = 0;
@@ -91,14 +97,22 @@ pub(crate) fn to_magnitude_and_suffix(n: u128, suffix_type: SuffixType) -> Strin
9197
let suffix = suffixes[i];
9298

9399
if rem == 0 {
94-
format!("{quot}{suffix}")
100+
if add_tracing_zero && !suffix.is_empty() && quot != 0 && quot <= 9 {
101+
format!("{quot}.0{suffix}")
102+
} else {
103+
format!("{quot}{suffix}")
104+
}
95105
} else {
96106
let tenths_place = rem / (bases[i] / 10);
97107

98108
if rem % (bases[i] / 10) == 0 {
99109
format!("{quot}.{tenths_place}{suffix}")
100110
} else if tenths_place + 1 == 10 || quot >= 10 {
101-
format!("{}{suffix}", quot + 1)
111+
if add_tracing_zero && !suffix.is_empty() && quot != 0 && quot < 9 {
112+
format!("{}.0{suffix}", quot + 1)
113+
} else {
114+
format!("{}{suffix}", quot + 1)
115+
}
102116
} else {
103117
format!("{quot}.{}{suffix}", tenths_place + 1)
104118
}
@@ -150,6 +164,18 @@ impl BlockSize {
150164
Self::Bytes(n) => n,
151165
}
152166
}
167+
168+
pub(crate) fn to_header(&self) -> String {
169+
match self {
170+
Self::Bytes(n) => {
171+
if n % 1024 == 0 && n % 1000 != 0 {
172+
to_magnitude_and_suffix(*n as u128, SuffixType::Iec, false)
173+
} else {
174+
to_magnitude_and_suffix(*n as u128, SuffixType::Si, false)
175+
}
176+
}
177+
}
178+
}
153179
}
154180

155181
impl Default for BlockSize {
@@ -196,9 +222,9 @@ impl fmt::Display for BlockSize {
196222
match self {
197223
Self::Bytes(n) => {
198224
let s = if n % 1024 == 0 && n % 1000 != 0 {
199-
to_magnitude_and_suffix(*n as u128, SuffixType::Iec)
225+
to_magnitude_and_suffix(*n as u128, SuffixType::Iec, true)
200226
} else {
201-
to_magnitude_and_suffix(*n as u128, SuffixType::Si)
227+
to_magnitude_and_suffix(*n as u128, SuffixType::Si, true)
202228
};
203229

204230
write!(f, "{s}")
@@ -216,75 +242,121 @@ mod tests {
216242

217243
#[test]
218244
fn test_to_magnitude_and_suffix_powers_of_1024() {
219-
assert_eq!(to_magnitude_and_suffix(1024, SuffixType::Iec), "1K");
220-
assert_eq!(to_magnitude_and_suffix(2048, SuffixType::Iec), "2K");
221-
assert_eq!(to_magnitude_and_suffix(4096, SuffixType::Iec), "4K");
222-
assert_eq!(to_magnitude_and_suffix(1024 * 1024, SuffixType::Iec), "1M");
245+
assert_eq!(to_magnitude_and_suffix(1024, SuffixType::Iec, true), "1.0K");
246+
assert_eq!(to_magnitude_and_suffix(10240, SuffixType::Iec, true), "10K");
247+
assert_eq!(to_magnitude_and_suffix(2048, SuffixType::Iec, false), "2K");
223248
assert_eq!(
224-
to_magnitude_and_suffix(2 * 1024 * 1024, SuffixType::Iec),
225-
"2M"
249+
to_magnitude_and_suffix(1024 * 40, SuffixType::Iec, false),
250+
"40K"
226251
);
227252
assert_eq!(
228-
to_magnitude_and_suffix(1024 * 1024 * 1024, SuffixType::Iec),
229-
"1G"
253+
to_magnitude_and_suffix(1024 * 1024, SuffixType::Iec, true),
254+
"1.0M"
230255
);
231256
assert_eq!(
232-
to_magnitude_and_suffix(34 * 1024 * 1024 * 1024, SuffixType::Iec),
257+
to_magnitude_and_suffix(2 * 1024 * 1024, SuffixType::Iec, true),
258+
"2.0M"
259+
);
260+
assert_eq!(
261+
to_magnitude_and_suffix(1024 * 1024 * 1024, SuffixType::Iec, true),
262+
"1.0G"
263+
);
264+
assert_eq!(
265+
to_magnitude_and_suffix(34 * 1024 * 1024 * 1024, SuffixType::Iec, true),
233266
"34G"
234267
);
235268
}
236269

237270
#[test]
238271
#[allow(clippy::cognitive_complexity)]
239272
fn test_to_magnitude_and_suffix_not_powers_of_1024() {
240-
assert_eq!(to_magnitude_and_suffix(1, SuffixType::Si), "1B");
241-
assert_eq!(to_magnitude_and_suffix(999, SuffixType::Si), "999B");
242-
243-
assert_eq!(to_magnitude_and_suffix(1000, SuffixType::Si), "1kB");
244-
assert_eq!(to_magnitude_and_suffix(1001, SuffixType::Si), "1.1kB");
245-
assert_eq!(to_magnitude_and_suffix(1023, SuffixType::Si), "1.1kB");
246-
assert_eq!(to_magnitude_and_suffix(1025, SuffixType::Si), "1.1kB");
247-
assert_eq!(to_magnitude_and_suffix(10_001, SuffixType::Si), "11kB");
248-
assert_eq!(to_magnitude_and_suffix(999_000, SuffixType::Si), "999kB");
249-
250-
assert_eq!(to_magnitude_and_suffix(999_001, SuffixType::Si), "1MB");
251-
assert_eq!(to_magnitude_and_suffix(999_999, SuffixType::Si), "1MB");
252-
assert_eq!(to_magnitude_and_suffix(1_000_000, SuffixType::Si), "1MB");
253-
assert_eq!(to_magnitude_and_suffix(1_000_001, SuffixType::Si), "1.1MB");
254-
assert_eq!(to_magnitude_and_suffix(1_100_000, SuffixType::Si), "1.1MB");
255-
assert_eq!(to_magnitude_and_suffix(1_100_001, SuffixType::Si), "1.2MB");
256-
assert_eq!(to_magnitude_and_suffix(1_900_000, SuffixType::Si), "1.9MB");
257-
assert_eq!(to_magnitude_and_suffix(1_900_001, SuffixType::Si), "2MB");
258-
assert_eq!(to_magnitude_and_suffix(9_900_000, SuffixType::Si), "9.9MB");
259-
assert_eq!(to_magnitude_and_suffix(9_900_001, SuffixType::Si), "10MB");
273+
assert_eq!(to_magnitude_and_suffix(1, SuffixType::Si, true), "1.0B");
274+
assert_eq!(to_magnitude_and_suffix(999, SuffixType::Si, true), "999B");
275+
276+
assert_eq!(to_magnitude_and_suffix(1000, SuffixType::Si, true), "1.0kB");
277+
assert_eq!(to_magnitude_and_suffix(1001, SuffixType::Si, true), "1.1kB");
278+
assert_eq!(to_magnitude_and_suffix(1023, SuffixType::Si, true), "1.1kB");
279+
assert_eq!(to_magnitude_and_suffix(1025, SuffixType::Si, true), "1.1kB");
260280
assert_eq!(
261-
to_magnitude_and_suffix(999_000_000, SuffixType::Si),
281+
to_magnitude_and_suffix(10_001, SuffixType::Si, true),
282+
"11kB"
283+
);
284+
assert_eq!(
285+
to_magnitude_and_suffix(999_000, SuffixType::Si, true),
286+
"999kB"
287+
);
288+
289+
assert_eq!(
290+
to_magnitude_and_suffix(999_001, SuffixType::Si, true),
291+
"1.0MB"
292+
);
293+
assert_eq!(
294+
to_magnitude_and_suffix(999_999, SuffixType::Si, true),
295+
"1.0MB"
296+
);
297+
assert_eq!(
298+
to_magnitude_and_suffix(1_000_000, SuffixType::Si, true),
299+
"1.0MB"
300+
);
301+
assert_eq!(
302+
to_magnitude_and_suffix(1_000_001, SuffixType::Si, true),
303+
"1.1MB"
304+
);
305+
assert_eq!(
306+
to_magnitude_and_suffix(1_100_000, SuffixType::Si, true),
307+
"1.1MB"
308+
);
309+
assert_eq!(
310+
to_magnitude_and_suffix(1_100_001, SuffixType::Si, true),
311+
"1.2MB"
312+
);
313+
assert_eq!(
314+
to_magnitude_and_suffix(1_900_000, SuffixType::Si, true),
315+
"1.9MB"
316+
);
317+
assert_eq!(
318+
to_magnitude_and_suffix(1_900_001, SuffixType::Si, true),
319+
"2.0MB"
320+
);
321+
assert_eq!(
322+
to_magnitude_and_suffix(9_900_000, SuffixType::Si, true),
323+
"9.9MB"
324+
);
325+
assert_eq!(
326+
to_magnitude_and_suffix(9_900_001, SuffixType::Si, true),
327+
"10MB"
328+
);
329+
assert_eq!(
330+
to_magnitude_and_suffix(999_000_000, SuffixType::Si, true),
262331
"999MB"
263332
);
264333

265-
assert_eq!(to_magnitude_and_suffix(999_000_001, SuffixType::Si), "1GB");
266334
assert_eq!(
267-
to_magnitude_and_suffix(1_000_000_000, SuffixType::Si),
268-
"1GB"
335+
to_magnitude_and_suffix(999_000_001, SuffixType::Si, true),
336+
"1.0GB"
337+
);
338+
assert_eq!(
339+
to_magnitude_and_suffix(1_000_000_000, SuffixType::Si, true),
340+
"1.0GB"
269341
);
270342
assert_eq!(
271-
to_magnitude_and_suffix(1_000_000_001, SuffixType::Si),
343+
to_magnitude_and_suffix(1_000_000_001, SuffixType::Si, true),
272344
"1.1GB"
273345
);
274346
}
275347

276348
#[test]
277349
fn test_block_size_display() {
278-
assert_eq!(format!("{}", BlockSize::Bytes(1024)), "1K");
279-
assert_eq!(format!("{}", BlockSize::Bytes(2 * 1024)), "2K");
280-
assert_eq!(format!("{}", BlockSize::Bytes(3 * 1024 * 1024)), "3M");
350+
assert_eq!(format!("{}", BlockSize::Bytes(1024)), "1.0K");
351+
assert_eq!(format!("{}", BlockSize::Bytes(2 * 1024)), "2.0K");
352+
assert_eq!(format!("{}", BlockSize::Bytes(3 * 1024 * 1024)), "3.0M");
281353
}
282354

283355
#[test]
284356
fn test_block_size_display_multiples_of_1000_and_1024() {
285357
assert_eq!(format!("{}", BlockSize::Bytes(128_000)), "128kB");
286358
assert_eq!(format!("{}", BlockSize::Bytes(1000 * 1024)), "1.1MB");
287-
assert_eq!(format!("{}", BlockSize::Bytes(1_000_000_000_000)), "1TB");
359+
assert_eq!(format!("{}", BlockSize::Bytes(1_000_000_000_000)), "1.0TB");
288360
}
289361

290362
#[test]

src/uu/df/src/table.rs

Lines changed: 28 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -264,7 +264,7 @@ impl<'a> RowFormatter<'a> {
264264
/// The scaling factor is defined in the `options` field.
265265
fn scaled_bytes(&self, size: u64) -> Cell {
266266
let s = if let Some(h) = self.options.human_readable {
267-
to_magnitude_and_suffix(size.into(), SuffixType::HumanReadable(h))
267+
to_magnitude_and_suffix(size.into(), SuffixType::HumanReadable(h), true)
268268
} else {
269269
let BlockSize::Bytes(d) = self.options.block_size;
270270
(size as f64 / d as f64).ceil().to_string()
@@ -277,7 +277,7 @@ impl<'a> RowFormatter<'a> {
277277
/// The scaling factor is defined in the `options` field.
278278
fn scaled_inodes(&self, size: u128) -> Cell {
279279
let s = if let Some(h) = self.options.human_readable {
280-
to_magnitude_and_suffix(size, SuffixType::HumanReadable(h))
280+
to_magnitude_and_suffix(size, SuffixType::HumanReadable(h), true)
281281
} else {
282282
size.to_string()
283283
};
@@ -381,7 +381,11 @@ impl Header {
381381
translate!("df-blocks-suffix")
382382
)
383383
}
384-
_ => format!("{}{}", options.block_size, translate!("df-blocks-suffix")),
384+
_ => format!(
385+
"{}{}",
386+
options.block_size.to_header(),
387+
translate!("df-blocks-suffix")
388+
),
385389
},
386390
Column::Used => translate!("df-header-used"),
387391
Column::Avail => match options.header_mode {
@@ -826,17 +830,25 @@ mod tests {
826830
fs_type: "my_type".to_string(),
827831
fs_mount: "my_mount".into(),
828832

829-
bytes: 4000,
833+
bytes: 40000,
830834
bytes_used: 1000,
831-
bytes_avail: 3000,
832-
bytes_usage: Some(0.25),
835+
bytes_avail: 39000,
836+
bytes_usage: Some(0.025),
833837

834838
..Default::default()
835839
};
836840
let fmt = RowFormatter::new(&row, &options, false);
837841
assert!(compare_cell_content(
838842
fmt.get_cells(),
839-
vec!("my_device", "my_type", "4k", "1k", "3k", "25%", "my_mount")
843+
vec!(
844+
"my_device",
845+
"my_type",
846+
"40k",
847+
"1.0k",
848+
"39k",
849+
"3%",
850+
"my_mount"
851+
)
840852
));
841853
}
842854

@@ -863,7 +875,15 @@ mod tests {
863875
let fmt = RowFormatter::new(&row, &options, false);
864876
assert!(compare_cell_content(
865877
fmt.get_cells(),
866-
vec!("my_device", "my_type", "4K", "1K", "3K", "25%", "my_mount")
878+
vec!(
879+
"my_device",
880+
"my_type",
881+
"4.0K",
882+
"1.0K",
883+
"3.0K",
884+
"25%",
885+
"my_mount"
886+
)
867887
));
868888
}
869889

0 commit comments

Comments
 (0)