1use std::cmp::min;
4use std::default::Default;
5use std::ops::Deref;
6use std::sync::atomic::{AtomicUsize, Ordering};
7use std::sync::{Arc, Weak};
8
9use crate::spinlock::{SpinLock, SpinLockGuard};
10use crate::{MatchRange, Rank, SkimItem};
11
12#[derive(Debug)]
15pub struct RankBuilder {
16 criterion: Vec<RankCriteria>,
17}
18
19impl Default for RankBuilder {
20 fn default() -> Self {
21 Self {
22 criterion: vec![RankCriteria::Score, RankCriteria::Begin, RankCriteria::End],
23 }
24 }
25}
26
27impl RankBuilder {
28 pub fn new(mut criterion: Vec<RankCriteria>) -> Self {
29 if !criterion.contains(&RankCriteria::Score) && !criterion.contains(&RankCriteria::NegScore) {
30 criterion.insert(0, RankCriteria::Score);
31 }
32
33 criterion.dedup();
34 Self { criterion }
35 }
36
37 pub fn build_rank(&self, score: i32, begin: usize, end: usize, length: usize, item_idx: usize) -> Rank {
39 let mut rank = [0; 4];
40 let begin = begin as i32;
41 let end = end as i32;
42 let length = length as i32;
43 let item_idx = item_idx as i32;
44
45 self.criterion.iter().take(4).enumerate().for_each(|(index, criteria)| {
46 let value = match criteria {
47 RankCriteria::Index => item_idx,
48 RankCriteria::NegIndex => -item_idx,
49 RankCriteria::Score => -score,
50 RankCriteria::Begin => begin,
51 RankCriteria::End => end,
52 RankCriteria::NegScore => score,
53 RankCriteria::NegBegin => -begin,
54 RankCriteria::NegEnd => -end,
55 RankCriteria::Length => length,
56 RankCriteria::NegLength => -length,
57 };
58
59 rank[index] = value;
60 });
61
62 rank
63 }
64}
65
66#[derive(Clone)]
68pub struct MatchedItem {
69 pub item: Weak<dyn SkimItem>,
70 pub rank: Rank,
71 pub matched_range: Option<MatchRange>, pub item_idx: u32,
73}
74
75impl MatchedItem {
76 pub fn upgrade_infallible(&self) -> Arc<dyn SkimItem> {
77 self.item.upgrade().unwrap_or(Arc::new(""))
78 }
79}
80
81use std::cmp::Ordering as CmpOrd;
82
83impl PartialEq for MatchedItem {
84 fn eq(&self, other: &Self) -> bool {
85 self.rank.eq(&other.rank)
86 }
87}
88
89impl std::cmp::Eq for MatchedItem {}
90
91impl PartialOrd for MatchedItem {
92 fn partial_cmp(&self, other: &Self) -> Option<CmpOrd> {
93 self.rank.partial_cmp(&other.rank)
94 }
95}
96
97impl Ord for MatchedItem {
98 fn cmp(&self, other: &Self) -> CmpOrd {
99 self.rank.cmp(&other.rank)
100 }
101}
102
103use crate::reader::ITEMS_INITIAL_CAPACITY;
106
107pub struct ItemPool {
108 length: AtomicUsize,
109 pool: SpinLock<Vec<Arc<dyn SkimItem>>>,
110 taken: AtomicUsize,
112
113 reserved_items: SpinLock<Vec<Weak<dyn SkimItem>>>,
115 lines_to_reserve: usize,
116}
117
118impl Drop for ItemPool {
119 fn drop(&mut self) {
120 let _reserved_items = std::mem::take(&mut *self.reserved_items.lock());
121 let _pool = std::mem::take(&mut *self.pool.lock());
122 }
123}
124
125impl Default for ItemPool {
126 fn default() -> Self {
127 ItemPool::new()
128 }
129}
130
131impl ItemPool {
132 pub fn new() -> Self {
133 Self {
134 length: AtomicUsize::new(0),
135 pool: SpinLock::new(Vec::with_capacity(ITEMS_INITIAL_CAPACITY)),
136 taken: AtomicUsize::new(0),
137 reserved_items: SpinLock::new(Vec::new()),
138 lines_to_reserve: 0,
139 }
140 }
141
142 pub fn lines_to_reserve(mut self, lines_to_reserve: usize) -> Self {
143 self.lines_to_reserve = lines_to_reserve;
144 self
145 }
146
147 pub fn len(&self) -> usize {
148 self.length.load(Ordering::SeqCst)
149 }
150
151 pub fn num_not_taken(&self) -> usize {
152 self.length.load(Ordering::SeqCst) - self.taken.load(Ordering::SeqCst)
153 }
154
155 pub fn num_taken(&self) -> usize {
156 self.taken.load(Ordering::SeqCst)
157 }
158
159 pub fn clear(&self) {
160 let mut items = self.pool.lock();
161 items.clear();
162 let mut header_items = self.reserved_items.lock();
163 header_items.clear();
164 self.taken.store(0, Ordering::SeqCst);
165 self.length.store(0, Ordering::SeqCst);
166 }
167
168 pub fn reset(&self) {
169 let _items = self.pool.lock();
171 self.taken.store(0, Ordering::SeqCst);
172 }
173
174 pub fn append(&self, items: &mut Vec<Arc<dyn SkimItem>>) -> usize {
176 let len = items.len();
177 trace!("item pool, append {} items", len);
178 let mut pool = self.pool.lock();
179 let mut header_items = self.reserved_items.lock();
180
181 let to_reserve = self.lines_to_reserve - header_items.len();
182 if to_reserve > 0 {
183 let to_reserve = min(to_reserve, items.len());
184 let mut reserved_pool = items[..to_reserve].to_vec();
185 pool.append(&mut reserved_pool);
186 let mut reserved_header: Vec<Weak<dyn SkimItem>> = reserved_pool.iter().map(Arc::downgrade).collect();
187 header_items.append(&mut reserved_header);
188 } else {
189 pool.append(items);
190 }
191
192 self.length.store(pool.len(), Ordering::SeqCst);
193 trace!("item pool, done append {} items", len);
194 pool.len()
195 }
196
197 pub fn take(&self) -> ItemPoolGuard<'_, Arc<dyn SkimItem>> {
198 let guard = self.pool.lock();
199 let taken = self.taken.swap(guard.len(), Ordering::SeqCst);
200 ItemPoolGuard { guard, start: taken }
201 }
202
203 pub fn reserved(&self) -> ItemPoolGuard<'_, Weak<dyn SkimItem>> {
204 let guard = self.reserved_items.lock();
205 ItemPoolGuard { guard, start: 0 }
206 }
207}
208
209pub struct ItemPoolGuard<'a, T: Sized + 'a> {
210 guard: SpinLockGuard<'a, Vec<T>>,
211 start: usize,
212}
213
214impl<'mutex, T: Sized> Deref for ItemPoolGuard<'mutex, T> {
215 type Target = [T];
216
217 fn deref(&self) -> &[T] {
218 &self.guard[self.start..]
219 }
220}
221
222#[derive(Debug, PartialEq, Eq, Clone, Copy)]
224pub enum RankCriteria {
225 Index,
226 NegIndex,
227 Score,
228 Begin,
229 End,
230 NegScore,
231 NegBegin,
232 NegEnd,
233 Length,
234 NegLength,
235}
236
237pub fn parse_criteria(text: &str) -> Option<RankCriteria> {
238 match text.to_lowercase().as_ref() {
239 "score" => Some(RankCriteria::Score),
240 "begin" => Some(RankCriteria::Begin),
241 "end" => Some(RankCriteria::End),
242 "-score" => Some(RankCriteria::NegScore),
243 "-begin" => Some(RankCriteria::NegBegin),
244 "-end" => Some(RankCriteria::NegEnd),
245 "length" => Some(RankCriteria::Length),
246 "-length" => Some(RankCriteria::NegLength),
247 "index" => Some(RankCriteria::Index),
248 "-index" => Some(RankCriteria::NegIndex),
249 _ => None,
250 }
251}