1use std::fs;
2use std::path::Path;
3
4#[derive(Debug, Clone, Copy, PartialEq)]
5pub enum UnitSystem {
6 Decimal, Binary, Both,
9 None,
10}
11
12#[derive(Debug, Clone)]
13pub struct WeightConfig {
14 pub system: UnitSystem,
15 pub precision: usize, pub show_for_files: bool,
17 pub show_for_dirs: bool,
18 pub dir_sum_included: bool, }
20
21impl Default for WeightConfig {
22 fn default() -> Self {
23 Self {
24 system: UnitSystem::Decimal,
25 precision: 5,
26 show_for_files: true,
27 show_for_dirs: true,
28 dir_sum_included: true,
29 }
30 }
31}
32
33pub fn format_weight(bytes: u64, config: &WeightConfig) -> String {
35 if config.system == UnitSystem::None {
36 return String::new();
37 }
38
39 let (base, units) = match config.system {
40 UnitSystem::Binary => (1024.0_f64, vec!["B", "KiB", "MiB", "GiB", "TiB", "PiB"]),
41 _ => (1000.0_f64, vec!["B", "kB", "MB", "GB", "TB", "PB"]),
42 };
43
44 if bytes == 0 {
45 return format!(
46 "[{:>2} {:>width$}] ",
47 units[0],
48 "0",
49 width = config.precision
50 );
51 }
52
53 let bytes_f = bytes as f64;
54 let exp = (bytes_f.ln() / base.ln()).floor() as usize;
55 let exp = exp.min(units.len() - 1);
56 let value = bytes_f / base.powi(exp as i32);
57 let unit = units[exp];
58
59 let formatted_value = format_value_with_precision(value, config.precision);
61
62 format!("[{:>3} {}] ", unit, formatted_value)
63}
64
65fn format_value_with_precision(value: f64, width: usize) -> String {
66 let integer_part = value.floor() as u64;
68 let integer_str = integer_part.to_string();
69 let int_len = integer_str.len();
70
71 if int_len >= width {
72 return integer_str[..width].to_string();
74 }
75
76 let available_precision = if width > int_len + 1 {
78 width - int_len - 1
79 } else {
80 0
81 };
82
83 let formatted = format!("{:.1$}", value, available_precision);
84
85 if formatted.len() > width {
87 formatted[..width].trim_end_matches('.').to_string()
88 } else {
89 format!("{:>width$}", formatted, width = width)
90 }
91}
92
93pub fn get_path_weight(path: &Path, sum_included_only: bool) -> u64 {
95 let metadata = match fs::metadata(path) {
96 Ok(m) => m,
97 Err(_) => return 0,
98 };
99
100 if metadata.is_file() {
101 return metadata.len();
102 }
103
104 if metadata.is_dir() && !sum_included_only {
105 return get_dir_size(path);
107 }
108
109 0 }
111
112fn get_dir_size(path: &Path) -> u64 {
113 fs::read_dir(path)
114 .map(|entries| {
115 entries
116 .filter_map(|e| e.ok())
117 .map(|e| {
118 let p = e.path();
119 if p.is_dir() {
120 get_dir_size(&p)
121 } else {
122 e.metadata().map(|m| m.len()).unwrap_or(0)
123 }
124 })
125 .sum()
126 })
127 .unwrap_or(0)
128}