use std::sync::{Arc, mpsc};
use ignore::WalkBuilder;
use super::{FileEntry, WalkConfig, filter::process_path, traverse::CodeWalker};
pub(crate) const PARALLEL_CHANNEL_CAPACITY: usize = 8_192;
impl CodeWalker {
#[must_use]
pub fn walk_parallel(&self, threads: usize) -> mpsc::Receiver<crate::error::Result<FileEntry>> {
let (tx, rx) = mpsc::sync_channel(PARALLEL_CHANNEL_CAPACITY);
let config = Arc::new(self.config.clone());
let walker = self.build_parallel_walker(threads, Arc::clone(&config));
std::thread::spawn(move || {
walker.run(|| {
let tx = tx.clone();
let config = Arc::clone(&config);
Box::new(move |result| {
let entry_result = match result {
Ok(entry) => match entry.file_type() {
Some(ft) if ft.is_file() => {
match process_path(entry.path(), config.as_ref()) {
Ok(Some(file_entry)) => Ok(file_entry),
Ok(None) => return ignore::WalkState::Continue,
Err(err) => Err(err),
}
}
_ => return ignore::WalkState::Continue,
},
Err(err) => Err(crate::error::CodewalkError::Ignore(err)),
};
if tx.send(entry_result).is_err() {
return ignore::WalkState::Quit;
}
ignore::WalkState::Continue
})
});
});
rx
}
pub(crate) fn build_parallel_walker(
&self,
threads: usize,
_config: Arc<WalkConfig>,
) -> ignore::WalkParallel {
let mut builder = WalkBuilder::new(&self.root);
self.configure_builder(&mut builder);
builder.threads(threads);
builder.build_parallel()
}
}
#[cfg(test)]
mod tests {
#![allow(clippy::unwrap_used)]
use super::*;
use crate::walker::test_utils::setup_test_dir;
#[test]
fn parallel_walk() {
let dir = setup_test_dir();
let walker = CodeWalker::new(dir.path(), WalkConfig::default());
let rx = walker.walk_parallel(2);
let entries: Vec<FileEntry> = rx.iter().collect::<Result<Vec<_>, _>>().unwrap();
assert!(entries.len() >= 2);
}
}