1use f00_core::BlockSize;
2
3pub fn human_size(bytes: u64) -> String {
5 human_size_base(bytes, 1024)
6}
7
8pub fn human_size_si(bytes: u64) -> String {
10 human_size_base(bytes, 1000)
11}
12
13fn human_size_base(bytes: u64, base: u64) -> String {
14 const UNITS: [&str; 6] = ["B", "K", "M", "G", "T", "P"];
15 if bytes < base {
16 return format!("{bytes}");
17 }
18
19 let mut value = bytes as f64;
20 let mut unit = 0;
21 let base_f = base as f64;
22 while value >= base_f && unit < UNITS.len() - 1 {
23 value /= base_f;
24 unit += 1;
25 }
26
27 if value >= 10.0 || unit == 0 {
28 format!("{:.0}{}", value, UNITS[unit])
29 } else {
30 format!("{:.1}{}", value, UNITS[unit])
31 }
32}
33
34pub fn block_display(blocks_512: u64) -> u64 {
40 block_display_with_unit(blocks_512, 1024)
41}
42
43pub fn block_display_with_unit(blocks_512: u64, unit_bytes: u64) -> u64 {
45 let unit = unit_bytes.max(1);
46 let bytes = blocks_512.saturating_mul(512);
47 bytes.div_ceil(unit)
48}
49
50pub fn format_size_bytes(bytes: u64, block_size: BlockSize, human: bool, si: bool) -> String {
52 if human || matches!(block_size, BlockSize::HumanBinary) {
53 return if si || matches!(block_size, BlockSize::HumanSi) {
54 human_size_si(bytes)
55 } else {
56 human_size(bytes)
57 };
58 }
59 if si || matches!(block_size, BlockSize::HumanSi) {
60 return human_size_si(bytes);
61 }
62 match block_size {
63 BlockSize::Bytes(1) | BlockSize::Bytes(0) => bytes.to_string(),
64 BlockSize::Bytes(unit) => {
65 let n = bytes.div_ceil(unit.max(1));
66 n.to_string()
67 }
68 BlockSize::HumanBinary => human_size(bytes),
69 BlockSize::HumanSi => human_size_si(bytes),
70 }
71}
72
73#[cfg(test)]
74mod tests {
75 use super::*;
76
77 #[test]
78 fn small_sizes_are_plain() {
79 assert_eq!(human_size(0), "0");
80 assert_eq!(human_size(999), "999");
81 }
82
83 #[test]
84 fn kilobytes() {
85 assert_eq!(human_size(1024), "1.0K");
86 assert_eq!(human_size(1536), "1.5K");
87 assert_eq!(human_size(10 * 1024), "10K");
88 }
89
90 #[test]
91 fn si_uses_1000() {
92 assert_eq!(human_size_si(1000), "1.0K");
93 assert_eq!(human_size_si(1000 * 1000), "1.0M");
94 }
95
96 #[test]
97 fn block_display_rounds() {
98 assert_eq!(block_display(1), 1);
99 assert_eq!(block_display(2), 1);
100 assert_eq!(block_display(3), 2);
101 }
102
103 #[test]
104 fn block_display_custom_unit() {
105 assert_eq!(block_display_with_unit(2, 512), 2);
107 assert_eq!(block_display_with_unit(2, 1024), 1);
109 }
110}