11use std:: collections:: HashSet ;
22use std:: fs;
3- use std:: path:: PathBuf ;
3+ use std:: path:: { Path , PathBuf } ;
44use std:: thread;
55
66use crossbeam_channel as channel;
@@ -23,11 +23,60 @@ pub enum Directories {
2323 Excluded ,
2424}
2525
26+ #[ derive( Debug ) ]
2627pub enum Error {
2728 NoMetadataForPath ( PathBuf ) ,
2829 CouldNotReadDir ( PathBuf ) ,
2930}
3031
32+ /// The result of a disk usage computation.
33+ #[ derive( Debug ) ]
34+ pub struct DiskUsageResult {
35+ size_in_bytes : u64 ,
36+ errors : Vec < Error > ,
37+ }
38+
39+ impl DiskUsageResult {
40+ /// Returns the total size in bytes, or the errors if any occurred.
41+ pub fn size_in_bytes ( & self ) -> Result < u64 , & [ Error ] > {
42+ if self . errors . is_empty ( ) {
43+ Ok ( self . size_in_bytes )
44+ } else {
45+ Err ( & self . errors )
46+ }
47+ }
48+
49+ /// Ignore any errors and return a result that provides direct access to the size.
50+ pub fn ignore_errors ( & self ) -> UncheckedDiskUsageResult {
51+ UncheckedDiskUsageResult {
52+ size_in_bytes : self . size_in_bytes ,
53+ }
54+ }
55+
56+ /// Returns any errors encountered during traversal.
57+ pub fn errors ( & self ) -> & [ Error ] {
58+ & self . errors
59+ }
60+
61+ /// Returns `true` if no errors occurred during traversal.
62+ pub fn is_ok ( & self ) -> bool {
63+ self . errors . is_empty ( )
64+ }
65+ }
66+
67+ /// A disk usage result where errors have been explicitly ignored.
68+ #[ derive( Debug ) ]
69+ pub struct UncheckedDiskUsageResult {
70+ size_in_bytes : u64 ,
71+ }
72+
73+ impl UncheckedDiskUsageResult {
74+ /// Returns the total size in bytes.
75+ pub fn size_in_bytes ( & self ) -> u64 {
76+ self . size_in_bytes
77+ }
78+ }
79+
3180enum Message {
3281 SizeEntry ( Option < UniqueID > , u64 ) ,
3382 Error { error : Error } ,
@@ -88,19 +137,22 @@ fn walk(
88137 } ) ;
89138}
90139
91- /// Configure and run a parallel directory walk to file system usage.
92- pub struct DiskUsage < ' a > {
93- root_directories : & ' a [ PathBuf ] ,
140+ /// Configure and run a parallel directory walk to compute file system usage.
141+ pub struct DiskUsage {
142+ root_directories : Vec < PathBuf > ,
94143 num_workers : usize ,
95144 count_type : CountType ,
96145 directories : Directories ,
97146}
98147
99- impl < ' a > DiskUsage < ' a > {
148+ impl DiskUsage {
100149 /// Create a new DiskUsage builder for the given root directories.
101- pub fn new ( root_directories : & ' a [ PathBuf ] ) -> DiskUsage < ' a > {
150+ pub fn new < P : AsRef < Path > > ( root_directories : impl IntoIterator < Item = P > ) -> DiskUsage {
102151 DiskUsage {
103- root_directories,
152+ root_directories : root_directories
153+ . into_iter ( )
154+ . map ( |p| p. as_ref ( ) . to_path_buf ( ) )
155+ . collect ( ) ,
104156 num_workers : 1 ,
105157 count_type : CountType :: default ( ) ,
106158 directories : Directories :: default ( ) ,
@@ -125,14 +177,27 @@ impl<'a> DiskUsage<'a> {
125177 self
126178 }
127179
128- /// Run the count and return the total size in bytes, and any errors encountered.
129- pub fn count ( & self ) -> ( u64 , Vec < Error > ) {
180+ /// Run the count and return the result.
181+ pub fn count ( & self ) -> DiskUsageResult {
182+ let ( size_in_bytes, errors) = self . count_inner ( ) ;
183+ DiskUsageResult {
184+ size_in_bytes,
185+ errors,
186+ }
187+ }
188+
189+ /// Run the count and return only the size, ignoring any errors.
190+ pub fn count_ignoring_errors ( & self ) -> u64 {
191+ self . count_inner ( ) . 0
192+ }
193+
194+ fn count_inner ( & self ) -> ( u64 , Vec < Error > ) {
130195 let ( tx, rx) = channel:: unbounded ( ) ;
131196
132197 let receiver_thread = thread:: spawn ( move || {
133198 let mut total = 0 ;
134199 let mut ids = HashSet :: new ( ) ;
135- let mut error_messages : Vec < Error > = Vec :: new ( ) ;
200+ let mut errors : Vec < Error > = Vec :: new ( ) ;
136201 for msg in rx {
137202 match msg {
138203 Message :: SizeEntry ( unique_id, size) => {
@@ -146,18 +211,25 @@ impl<'a> DiskUsage<'a> {
146211 }
147212 }
148213 Message :: Error { error } => {
149- error_messages . push ( error) ;
214+ errors . push ( error) ;
150215 }
151216 }
152217 }
153- ( total, error_messages )
218+ ( total, errors )
154219 } ) ;
155220
156221 let pool = rayon:: ThreadPoolBuilder :: new ( )
157222 . num_threads ( self . num_workers )
158223 . build ( )
159224 . unwrap ( ) ;
160- pool. install ( || walk ( tx, self . root_directories , self . count_type , self . directories ) ) ;
225+ pool. install ( || {
226+ walk (
227+ tx,
228+ & self . root_directories ,
229+ self . count_type ,
230+ self . directories ,
231+ )
232+ } ) ;
161233
162234 receiver_thread. join ( ) . unwrap ( )
163235 }
0 commit comments