1use crate::Candidate;
7use crate::CandidateFilter;
8use crate::SearchOutput;
9use crate::SearchQuery;
10use crate::SearchSeparators;
11use crate::SearchStats;
12use crate::index::Indexes;
13use crate::search::SearchError;
14use crate::search::SearchOutcome;
15use crate::search::candidates::walk;
16use crate::search::request::SearchExecution;
17use rayon::prelude::*;
18
19pub struct GrepRequest<'a> {
21 pub indexes: &'a Indexes,
22 pub filter: &'a CandidateFilter,
23 pub output: SearchOutput,
24 pub separators: &'a SearchSeparators,
25 pub collect_stats: bool,
26}
27
28pub fn run(query: &SearchQuery, request: &GrepRequest<'_>) -> crate::Result<SearchOutcome> {
34 if query.opts.max_results == Some(0) {
35 return Err(crate::Error::Search(SearchError::InvalidMaxCount));
36 }
37
38 let spec = query.spec();
39 let output = request.output;
40
41 let raw = if request.indexes.is_empty() {
42 walk::collect_candidates(request.filter)?
43 } else {
44 let coverage = output.candidate_coverage();
45 request.indexes.candidates(&spec, coverage)
46 };
47
48 let candidates: Vec<Candidate> = raw
49 .into_par_iter()
50 .filter(|c| c.matches(request.filter))
51 .collect();
52
53 if candidates.is_empty() {
54 return Ok(SearchOutcome {
55 matched: false,
56 stats: request.collect_stats.then_some(SearchStats::default()),
57 });
58 }
59
60 query.search(&SearchExecution {
61 candidates,
62 output,
63 separators: request.separators,
64 collect_stats: request.collect_stats,
65 })
66}