91 lines
2.6 KiB
Rust
91 lines
2.6 KiB
Rust
use rayon::prelude::*;
|
|
|
|
use std::sync::mpsc::{Sender, channel};
|
|
use std::fs::{read_dir, DirEntry};
|
|
use std::io::Error;
|
|
use std::path::PathBuf;
|
|
use std::process::ExitCode;
|
|
|
|
use crate::Args;
|
|
use crate::directory::Directory;
|
|
|
|
pub fn walk<'a>(args: Args) -> Result<Directory, ExitCode> {
|
|
let (tx, rx) = channel();
|
|
|
|
let mut total = 0;
|
|
for entry in read_dir(&args.path).unwrap() {
|
|
let entry = match entry {
|
|
Ok(e) => e,
|
|
Err(e) => {
|
|
if !args.minimal {
|
|
eprintln!("unable to open {}: {e}", args.path);
|
|
}
|
|
if args.persistant {
|
|
continue;
|
|
} else {
|
|
return Err(ExitCode::FAILURE);
|
|
}
|
|
},
|
|
};
|
|
|
|
total += match total_entry(entry, &args, &tx) {
|
|
Ok(t) => t,
|
|
Err((path, error)) => {
|
|
if !args.minimal {
|
|
eprintln!("error opening {}: {error}", path.display());
|
|
}
|
|
if args.persistant {
|
|
continue;
|
|
} else {
|
|
return Err(ExitCode::FAILURE);
|
|
}
|
|
},
|
|
};
|
|
}
|
|
// drop this to close the channel, so that into_iter() can end
|
|
drop(tx);
|
|
|
|
let mut fs = Directory::make(args.path, total);
|
|
fs.extend(rx);
|
|
|
|
Ok(fs)
|
|
}
|
|
|
|
fn total_entry(entry: DirEntry, args: &Args, printer: &Sender<(PathBuf, u64)>) -> Result<u64, (PathBuf, Error)> {
|
|
let path = entry.path();
|
|
|
|
match path.read_dir() {
|
|
Ok(dir) => {
|
|
let result = dir.par_bridge()
|
|
.filter_map(Result::ok)
|
|
.map(|entry| total_entry(entry, args, printer))
|
|
.reduce(|| Ok(0), reduce_once);
|
|
|
|
if let Ok(size) = result {
|
|
if !args.minimal && !args.total_only {
|
|
let _ = printer.send((path, size));
|
|
}
|
|
}
|
|
|
|
return result;
|
|
},
|
|
Err(_) if path.is_file() => {
|
|
let size = unsafe { path.metadata().unwrap_unchecked() }.len();
|
|
if !args.minimal && !args.total_only {
|
|
let _ = printer.send((path, size));
|
|
}
|
|
return Ok(size);
|
|
},
|
|
Err(e) => Err((path, e)),
|
|
}
|
|
}
|
|
|
|
fn reduce_once<E>(accum: Result<u64, E>, this: Result<u64, E>) -> Result<u64, E> {
|
|
// reduction function for total_entry():
|
|
// short-circuit Errs, propagate Oks
|
|
// generic bc I'm lazy
|
|
match (accum, this) {
|
|
(Ok(n1), Ok(n2)) => Ok(n1 + n2),
|
|
(Err(e), _) | (_, Err(e)) => Err(e),
|
|
}
|
|
} |