Skip to content

Commit 44564fe

Browse files
committed
Update API
1 parent 6c5e96c commit 44564fe

File tree

4 files changed

+97
-27
lines changed

4 files changed

+97
-27
lines changed

src/lib.rs

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,16 +4,15 @@
44
//! use std::path::PathBuf;
55
//! use diskus::{DiskUsage, CountType};
66
//!
7-
//! let paths = vec![PathBuf::from(".")];
8-
//! let (size_in_bytes, errors) = DiskUsage::new(&paths)
7+
//! let result = DiskUsage::new(&["."])
98
//! .num_workers(4)
10-
//! .count_type(CountType::DiskUsage)
119
//! .count();
10+
//! let size_in_bytes = result.ignore_errors().size_in_bytes();
1211
//! ```
1312
1413
mod filesize;
1514
mod unique_id;
1615
pub mod walk;
1716

1817
pub use crate::filesize::CountType;
19-
pub use crate::walk::{Directories, DiskUsage, Error};
18+
pub use crate::walk::{Directories, DiskUsage, DiskUsageResult, Error};

src/main.rs

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,11 @@ use clap::{builder::PossibleValuesParser, Arg, ArgAction, Command};
44
use humansize::{format_size, FormatSizeOptions, BINARY, DECIMAL};
55
use num_format::{Locale, ToFormattedString};
66

7-
use diskus::{CountType, Directories, DiskUsage, Error};
7+
use diskus::{CountType, Directories, DiskUsage, DiskUsageResult, Error};
88

9-
fn print_result(size: u64, errors: &[Error], size_format: FormatSizeOptions, verbose: bool) {
9+
fn print_result(result: &DiskUsageResult, size_format: FormatSizeOptions, verbose: bool) {
1010
if verbose {
11-
for err in errors {
11+
for err in result.errors() {
1212
match err {
1313
Error::NoMetadataForPath(path) => {
1414
eprintln!(
@@ -24,12 +24,13 @@ fn print_result(size: u64, errors: &[Error], size_format: FormatSizeOptions, ver
2424
}
2525
}
2626
}
27-
} else if !errors.is_empty() {
27+
} else if !result.is_ok() {
2828
eprintln!(
2929
"[diskus warning] the results may be tainted. Re-run with -v/--verbose to print all errors."
3030
);
3131
}
3232

33+
let size = result.ignore_errors().size_in_bytes();
3334
if atty::is(atty::Stream::Stdout) {
3435
println!(
3536
"{} ({:} bytes)",
@@ -130,10 +131,10 @@ fn main() {
130131
_ => Directories::Auto,
131132
};
132133

133-
let (size, errors) = DiskUsage::new(&paths)
134+
let result = DiskUsage::new(paths)
134135
.num_workers(num_threads)
135136
.count_type(count_type)
136137
.directories(directories)
137138
.count();
138-
print_result(size, &errors, size_format, verbose);
139+
print_result(&result, size_format, verbose);
139140
}

src/walk.rs

Lines changed: 85 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
use std::collections::HashSet;
22
use std::fs;
3-
use std::path::PathBuf;
3+
use std::path::{Path, PathBuf};
44
use std::thread;
55

66
use crossbeam_channel as channel;
@@ -23,11 +23,60 @@ pub enum Directories {
2323
Excluded,
2424
}
2525

26+
#[derive(Debug)]
2627
pub 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+
3180
enum 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
}

tests/walk.rs

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -20,13 +20,11 @@ fn size_of_files_in_nested_directories() -> Result<(), Box<dyn Error>> {
2020
let file2_path = nested_dir.join("file-200-byte");
2121
File::create(&file2_path)?.write_all(&[0u8; 200])?;
2222

23-
let root_directories = vec![tmp_dir.path().to_path_buf()];
24-
let (size_in_bytes, errors) = DiskUsage::new(&root_directories)
23+
let result = DiskUsage::new(&[tmp_dir])
2524
.count_type(CountType::ApparentSize)
2625
.count();
2726

28-
assert!(errors.is_empty());
29-
assert_eq!(size_in_bytes, 300);
27+
assert_eq!(result.size_in_bytes().expect("no errors"), 300);
3028

3129
Ok(())
3230
}

0 commit comments

Comments
 (0)