use std::sync::Mutex;
use ignore::{DirEntry, WalkBuilder, WalkState};
pub trait Bucket: Default + Send {
fn merge_from(&mut self, other: Self);
}
impl<T: Send + 'static> Bucket for Vec<T> {
fn merge_from(&mut self, mut other: Self) {
self.append(&mut other);
}
}
pub fn parallel_walk<B, V>(builder: WalkBuilder, visit: V) -> B
where
B: Bucket + 'static,
V: Fn(&mut B, DirEntry) -> WalkState + Send + Sync,
{
let aggregate: Mutex<B> = Mutex::new(B::default());
let agg_ref: &Mutex<B> = &aggregate;
let visit_ref: &V = &visit;
builder.build_parallel().run(|| {
struct Flusher<'a, B: Bucket> {
local: B,
aggregate: &'a Mutex<B>,
}
impl<B: Bucket> Drop for Flusher<'_, B> {
fn drop(&mut self) {
let local = std::mem::take(&mut self.local);
self.aggregate.lock().unwrap().merge_from(local);
}
}
let mut flusher = Flusher {
local: B::default(),
aggregate: agg_ref,
};
Box::new(move |result| {
let Ok(entry) = result else {
return WalkState::Continue;
};
visit_ref(&mut flusher.local, entry)
})
});
aggregate.into_inner().unwrap()
}