rust_filesearch/fs/
size.rs1use crate::models::{Entry, EntryKind};
2use std::collections::HashMap;
3use std::path::PathBuf;
4
5pub fn compute_dir_sizes(entries: &[Entry]) -> HashMap<PathBuf, u64> {
7 let mut sizes: HashMap<PathBuf, u64> = HashMap::new();
8
9 for entry in entries {
11 if entry.kind == EntryKind::File {
12 sizes.insert(entry.path.clone(), entry.size);
14
15 let mut current = entry.path.parent();
17 while let Some(parent) = current {
18 *sizes.entry(parent.to_path_buf()).or_insert(0) += entry.size;
19 current = parent.parent();
20 }
21 }
22 }
23
24 sizes
25}
26
27pub fn update_entries_with_dir_sizes(entries: &mut [Entry], dir_sizes: &HashMap<PathBuf, u64>) {
29 for entry in entries.iter_mut() {
30 if entry.kind == EntryKind::Dir {
31 if let Some(&size) = dir_sizes.get(&entry.path) {
32 entry.size = size;
33 }
34 }
35 }
36}
37
38pub fn get_top_by_size(entries: &[Entry], n: usize) -> Vec<Entry> {
40 let mut sorted = entries.to_vec();
41 sorted.sort_by(|a, b| b.size.cmp(&a.size));
42 sorted.into_iter().take(n).collect()
43}
44
45pub fn compute_total_size(entries: &[Entry]) -> u64 {
47 entries.iter().map(|e| e.size).sum()
48}
49
50#[cfg(test)]
51mod tests {
52 use super::*;
53 use std::path::PathBuf;
54
55 fn make_entry(path: &str, size: u64, kind: EntryKind) -> Entry {
56 use chrono::Utc;
57
58 let path_buf = PathBuf::from(path);
59 let name = path_buf
60 .file_name()
61 .and_then(|n| n.to_str())
62 .unwrap_or("")
63 .to_string();
64
65 Entry {
66 path: path_buf,
67 name,
68 size,
69 kind,
70 mtime: Utc::now(),
71 perms: None,
72 owner: None,
73 depth: 0,
74 }
75 }
76
77 #[test]
78 fn test_compute_dir_sizes() {
79 use std::path::Path;
80
81 let entries = vec![
82 make_entry("/root", 0, EntryKind::Dir),
83 make_entry("/root/file1.txt", 100, EntryKind::File),
84 make_entry("/root/file2.txt", 200, EntryKind::File),
85 make_entry("/root/subdir", 0, EntryKind::Dir),
86 make_entry("/root/subdir/file3.txt", 50, EntryKind::File),
87 ];
88
89 let sizes = compute_dir_sizes(&entries);
90
91 assert_eq!(sizes.get(Path::new("/root")), Some(&350));
92 assert_eq!(sizes.get(Path::new("/root/subdir")), Some(&50));
93 }
94
95 #[test]
96 fn test_update_entries_with_dir_sizes() {
97 let mut entries = vec![
98 make_entry("/root", 0, EntryKind::Dir),
99 make_entry("/root/file.txt", 100, EntryKind::File),
100 ];
101
102 let sizes = compute_dir_sizes(&entries);
103 update_entries_with_dir_sizes(&mut entries, &sizes);
104
105 assert_eq!(entries[0].size, 100); assert_eq!(entries[1].size, 100); }
108
109 #[test]
110 fn test_get_top_by_size() {
111 let entries = vec![
112 make_entry("small.txt", 10, EntryKind::File),
113 make_entry("large.txt", 1000, EntryKind::File),
114 make_entry("medium.txt", 100, EntryKind::File),
115 ];
116
117 let top = get_top_by_size(&entries, 2);
118 assert_eq!(top.len(), 2);
119 assert_eq!(top[0].size, 1000);
120 assert_eq!(top[1].size, 100);
121 }
122
123 #[test]
124 fn test_compute_total_size() {
125 let entries = vec![
126 make_entry("file1.txt", 100, EntryKind::File),
127 make_entry("file2.txt", 200, EntryKind::File),
128 make_entry("file3.txt", 50, EntryKind::File),
129 ];
130
131 assert_eq!(compute_total_size(&entries), 350);
132 }
133}