1extern crate pad;
2
3use self::pad::PadStr;
4use colored::*;
5use std::cmp::Ordering;
6use std::fmt;
7use std::path::PathBuf;
8
9#[derive(Ord, Eq, PartialOrd, PartialEq, Copy, Clone)]
12pub struct FileSize {
13 size: u64,
14}
15
16impl FileSize {
17 pub fn new(i: u64) -> FileSize {
18 FileSize { size: i }
19 }
20
21 pub fn add(&mut self, other: FileSize) {
22 self.size += other.size;
23 }
24
25 pub fn get(self) -> u64 {
26 self.size
27 }
28}
29
30#[derive(Debug)]
31pub struct NamePair {
32 pub bytes: FileSize,
33 depth: u8,
34 pub name: String,
35 is_dir: bool,
36}
37
38fn sort_by_size(fst: &NamePair, snd: &NamePair) -> Ordering {
39 fst.bytes.cmp(&snd.bytes)
40}
41
42impl NamePair {
43 pub fn new(path: String, bytes_in: FileSize, d: u8, b: bool) -> NamePair {
44 NamePair {
45 name: path,
46 bytes: bytes_in,
47 depth: d,
48 is_dir: b,
49 }
50 }
51}
52
53pub struct FileTree {
54 pub file_size: FileSize,
55 files: Vec<NamePair>,
56}
57
58pub fn display_item(name: &str, bytes: FileSize) {
59 if bytes != FileSize::new(0) {
60 let to_formatted = format!("{}", bytes);
61 println!("{}\t {}", &to_formatted.green(), name);
62 }
63}
64
65impl Default for FileTree {
66 fn default() -> Self {
67 Self::new()
68 }
69}
70
71impl FileTree {
72 pub fn sort(
73 mut self,
74 maybe_num: Option<usize>,
75 min_bytes: Option<u64>,
76 dirs_only: bool,
77 max_depth: Option<u8>,
78 ) -> FileTree {
79 let self_size = if Some(self.file_size) > min_bytes.map(FileSize::new) {
80 self.file_size
81 } else {
82 FileSize::new(0)
83 };
84
85 if let Some(n) = maybe_num {
87 self.files.sort_by(|a, b| sort_by_size(b, a));
88 let new = self
89 .files
90 .into_iter()
91 .filter(|a| {
92 (if dirs_only { a.is_dir } else { true })
93 && Some(a.bytes) > min_bytes.map(FileSize::new)
94 && (max_depth.is_none() || Some(a.depth) <= max_depth)
95 })
96 .take(n)
97 .collect::<Vec<NamePair>>();
98 FileTree {
99 file_size: self_size,
100 files: new,
101 }
102 }
103 else {
105 self.files.sort_by(|a, b| sort_by_size(a, b));
106 let new = self
107 .files
108 .into_iter()
109 .filter(|a| {
110 (if dirs_only { a.is_dir } else { true })
111 && Some(a.bytes) > min_bytes.map(FileSize::new)
112 && (max_depth.is_none() || Some(a.depth) <= max_depth)
113 })
114 .collect::<Vec<NamePair>>();
115 FileTree {
116 file_size: self_size,
117 files: new,
118 }
119 }
120 }
121
122 pub fn filtered(
123 mut self,
124 min_bytes: Option<u64>,
125 dirs_only: bool,
126 max_depth: Option<u8>,
127 ) -> FileTree {
128 let self_size = if Some(self.file_size) > min_bytes.map(FileSize::new) {
129 self.file_size
130 } else {
131 FileSize::new(0)
132 };
133
134 self.files = self
135 .files
136 .into_iter()
137 .filter(|a| {
138 (if dirs_only { a.is_dir } else { true })
139 && Some(a.bytes) > min_bytes.map(FileSize::new)
140 && (max_depth.is_none() || Some(a.depth) <= max_depth)
141 })
142 .collect::<Vec<NamePair>>();
143
144 FileTree {
145 file_size: self_size,
146 files: self.files,
147 }
148 }
149
150 pub fn new() -> FileTree {
151 FileTree {
152 file_size: FileSize::new(0),
153 files: Vec::new(),
154 }
155 }
156
157 pub fn add(&mut self, size: FileSize) {
158 self.file_size.add(size);
159 }
160
161 pub fn push(
162 &mut self,
163 path: String,
164 size: FileSize,
165 subtree: Option<&mut FileTree>,
166 depth: u8,
167 is_dir: bool,
168 ) {
169 self.file_size.add(size);
171
172 if let Some(s) = subtree {
174 self.files.append(&mut s.files);
175 }
176
177 self.files.push(NamePair::new(path, size, depth, is_dir));
179 }
180
181 pub fn display_tree(&mut self, init_dir: &PathBuf) {
182 let vec = &self.files;
184 for name_pair in vec {
185 if name_pair.bytes != FileSize::new(0) {
186 let to_formatted = format!("{}", name_pair.bytes);
187 println!("{}\t {}", &to_formatted.green(), name_pair.name);
188 }
189 }
190
191 if self.file_size != FileSize::new(0) {
192 let to_formatted = format!("{}", self.file_size);
193 let path = init_dir.display();
194 println!("{}\t {}", &to_formatted.green(), path);
195 }
196 }
197}
198
199impl fmt::Debug for FileSize {
200 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
201 let pre_size = format!("{}", self.size);
202 write!(f, "{} b", &pre_size.pad_to_width(8))
203 }
204}
205
206impl fmt::Display for FileSize {
207 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
208 if self.size < 1024 {
209 let pre_size = format!("{}", self.size);
210 write!(f, "{} b", &pre_size.pad_to_width(4))
211 } else if self.size < 1048576 {
212 let pre_size = if self.size / 1024 > 9 {
213 format!("{}", self.size / 1024)
214 } else if self.size as f32 / 1024.0 >= 9.95 {
215 format!("{:.0}", self.size as f32 / 1024.0)
216 } else {
217 format!("{:.1}", self.size as f32 / 1024.0)
218 };
219 write!(f, "{} kB", &pre_size.pad_to_width(4))
220 } else if self.size < 1073741824 {
221 let pre_size = if self.size / 1048576 > 9 {
223 format!("{}", self.size / 1048576)
224 } else if self.size as f32 / 1048576.0 >= 9.95 {
225 format!("{:.0}", self.size as f32 / 1048576.0)
226 } else {
227 format!("{:.1}", self.size as f32 / 1048576.0)
228 };
229 write!(f, "{} MB", &pre_size.pad_to_width(4))
230 } else if self.size < 1099511627776 {
231 let pre_size = if self.size / 1073741824 > 9 {
233 format!("{}", self.size / 1073741824)
234 } else if self.size as f32 / 1073741824.0 >= 9.95 {
235 format!("{:.0}", self.size as f32 / 1073741824.0)
236 } else {
237 format!("{:.1}", self.size as f32 / 1073741824.0)
238 };
239 write!(f, "{} GB", &pre_size.pad_to_width(4))
240 } else {
241 let pre_size = if self.size / 1099511627776 > 9 {
243 format!("{}", self.size / 1099511627776)
244 } else if self.size as f32 / 1099511627776.0 >= 9.95 {
245 format!("{:.0}", self.size as f32 / 1099511627776.0)
246 } else {
247 format!("{:.1}", self.size as f32 / 1099511627776.0)
248 };
249 write!(f, "{} TB", &pre_size.pad_to_width(4))
250 }
251 }
252}