use std::sync::Arc;
use crate::engine::{run, EngineOptions, WalkConfig};
use crate::error::ParexError;
use crate::results::Results;
use crate::traits::{Matcher, Source};
pub struct SearchBuilder {
source: Option<Box<dyn Source>>,
matcher: Option<Box<dyn Matcher>>,
limit: Option<usize>,
threads: usize,
max_depth: Option<usize>,
collect_paths: bool,
collect_errors: bool,
}
impl Default for SearchBuilder {
fn default() -> Self {
Self {
source: None,
matcher: None,
limit: None,
threads: num_cpus(),
max_depth: None,
collect_paths: false,
collect_errors: false,
}
}
}
impl SearchBuilder {
pub fn source(mut self, s: impl Source + 'static) -> Self {
self.source = Some(Box::new(s));
self
}
pub fn with_matcher(mut self, m: impl Matcher + 'static) -> Self {
self.matcher = Some(Box::new(m));
self
}
pub fn matching(mut self, pattern: impl Into<String>) -> Self {
self.matcher = Some(Box::new(SubstringMatcher {
pattern: pattern.into().to_lowercase(),
}));
self
}
pub fn limit(mut self, n: usize) -> Self {
self.limit = Some(n);
self
}
pub fn threads(mut self, n: usize) -> Self {
self.threads = n;
self
}
pub fn max_depth(mut self, d: usize) -> Self {
self.max_depth = Some(d);
self
}
pub fn collect_paths(mut self, yes: bool) -> Self {
self.collect_paths = yes;
self
}
pub fn collect_errors(mut self, yes: bool) -> Self {
self.collect_errors = yes;
self
}
pub fn run(self) -> Result<Results, ParexError> {
let source = self
.source
.ok_or_else(|| ParexError::InvalidSource("no source provided".into()))?;
let matcher: Arc<dyn Matcher> = match self.matcher {
Some(m) => Arc::from(m),
None => Arc::new(AllMatcher),
};
let opts = EngineOptions {
config: WalkConfig {
threads: self.threads,
max_depth: self.max_depth,
limit: self.limit,
},
source,
matcher,
collect_paths: self.collect_paths,
collect_errors: self.collect_errors,
};
Ok(run(opts))
}
}
struct SubstringMatcher {
pattern: String,
}
impl Matcher for SubstringMatcher {
fn is_match(&self, entry: &crate::entry::Entry) -> bool {
entry.name.to_lowercase().contains(&self.pattern)
}
}
struct AllMatcher;
impl Matcher for AllMatcher {
fn is_match(&self, _entry: &crate::entry::Entry) -> bool {
true
}
}
fn num_cpus() -> usize {
std::thread::available_parallelism()
.map(|n| n.get())
.unwrap_or(4)
}