anshdadhich commited on
Commit
6fd27db
·
verified ·
1 Parent(s): c43eef0

Upload fastsearch-core/src/index/search.rs

Browse files
Files changed (1) hide show
  1. fastsearch-core/src/index/search.rs +126 -0
fastsearch-core/src/index/search.rs ADDED
@@ -0,0 +1,126 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ use rayon::prelude::*;
2
+ use crate::index::store::IndexStore;
3
+
4
+ const APP_EXTENSIONS: &[&str] = &["exe", "lnk", "msi", "appx", "msix"];
5
+ const APP_PATH_MARKERS: &[&str] = &[
6
+ "\\program files\\", "\\program files (x86)\\",
7
+ "\\start menu\\", "\\desktop\\", "\\appdata\\",
8
+ ];
9
+
10
+ #[derive(Debug, Clone)]
11
+ pub struct SearchResult {
12
+ pub full_path: std::path::PathBuf,
13
+ pub name: String,
14
+ pub rank: u8,
15
+ pub is_dir: bool,
16
+ }
17
+
18
+ pub fn search(
19
+ store: &IndexStore,
20
+ query: &str,
21
+ limit: usize,
22
+ case_sensitive: bool,
23
+ excluded_dirs: &[String],
24
+ ) -> Vec<SearchResult> {
25
+ if query.is_empty() {
26
+ return Vec::new();
27
+ }
28
+
29
+ let q = if case_sensitive { query.to_string() } else { query.to_lowercase() };
30
+
31
+ let entries = &store.entries;
32
+ let name_lower_arena = &store.name_lower_arena;
33
+ let name_arena = &store.name_arena;
34
+
35
+ let mut candidates: Vec<(u32, u8)> = entries
36
+ .par_iter()
37
+ .enumerate()
38
+ .filter_map(|(idx, entry)| {
39
+ let name_cmp = if case_sensitive {
40
+ unsafe { std::str::from_utf8_unchecked(&name_arena[entry.name_off as usize..(entry.name_off as usize + entry.name_len as usize)]) }
41
+ } else {
42
+ unsafe { std::str::from_utf8_unchecked(&name_lower_arena[entry.name_lower_off as usize..(entry.name_lower_off as usize + entry.name_lower_len as usize)]) }
43
+ };
44
+
45
+ let rank = if name_cmp == q { 1u8 }
46
+ else if name_cmp.starts_with(&q) { 2 }
47
+ else if name_cmp.contains(q.as_str()) { 3 }
48
+ else { return None; };
49
+
50
+ Some((idx as u32, rank))
51
+ })
52
+ .collect();
53
+
54
+ candidates.sort_unstable_by_key(|&(_, rank)| rank);
55
+ let overshoot = (limit * 5).max(1000);
56
+ candidates.truncate(overshoot);
57
+
58
+ let mut results: Vec<SearchResult> = Vec::with_capacity(limit);
59
+
60
+ for &(idx, base_rank) in &candidates {
61
+ let entry = &entries[idx as usize];
62
+ let full_path = build_path(entry.file_ref, store);
63
+
64
+ if !excluded_dirs.is_empty() {
65
+ let path_lower = full_path.to_string_lossy().to_lowercase();
66
+ if excluded_dirs.iter().any(|ex| path_lower.starts_with(ex.as_str())) {
67
+ continue;
68
+ }
69
+ }
70
+
71
+ let name_lower = store.name_lower(entry);
72
+ let rank = if base_rank <= 2 {
73
+ let ext_is_app = name_lower
74
+ .rsplit('.')
75
+ .next()
76
+ .map(|e| APP_EXTENSIONS.contains(&e))
77
+ .unwrap_or(false);
78
+ if ext_is_app {
79
+ let path_lower = full_path.to_string_lossy().to_lowercase();
80
+ if APP_PATH_MARKERS.iter().any(|m| path_lower.contains(m)) { 0 } else { base_rank }
81
+ } else {
82
+ base_rank
83
+ }
84
+ } else {
85
+ base_rank
86
+ };
87
+
88
+ results.push(SearchResult {
89
+ full_path,
90
+ name: store.name(entry).to_string(),
91
+ rank,
92
+ is_dir: entry.is_dir(),
93
+ });
94
+ }
95
+
96
+ results.sort_unstable_by_key(|r| r.rank);
97
+ results.truncate(limit);
98
+ results
99
+ }
100
+
101
+ /// Iterative path builder — walks parent chain via sorted ref_lookup.
102
+ pub fn build_path(file_ref: u64, store: &IndexStore) -> std::path::PathBuf {
103
+ let mut components: Vec<&str> = Vec::with_capacity(16);
104
+ let mut current = file_ref;
105
+
106
+ for _ in 0..64 {
107
+ match store.lookup_idx(current) {
108
+ Some(idx) => {
109
+ let entry = &store.entries[idx as usize];
110
+ components.push(store.name(entry));
111
+ if entry.parent_ref == current {
112
+ break;
113
+ }
114
+ current = entry.parent_ref;
115
+ }
116
+ None => break,
117
+ }
118
+ }
119
+
120
+ components.reverse();
121
+ let mut path = std::path::PathBuf::from(&store.drive_root);
122
+ for comp in components {
123
+ path.push(comp);
124
+ }
125
+ path
126
+ }