1use std::cmp::min;
4use std::default::Default;
5use std::ops::Deref;
6use std::sync::atomic::{AtomicUsize, Ordering};
7use std::sync::Arc;
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) -> 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
44 for (i, criteria) in self.criterion.iter().take(4).enumerate() {
45 let value = match criteria {
46 RankCriteria::Score => -score,
47 RankCriteria::Begin => begin,
48 RankCriteria::End => end,
49 RankCriteria::NegScore => score,
50 RankCriteria::NegBegin => -begin,
51 RankCriteria::NegEnd => -end,
52 RankCriteria::Length => length,
53 RankCriteria::NegLength => -length,
54 };
55
56 rank[i] = value;
57 }
58
59 rank
60 }
61}
62
63#[derive(Clone)]
65pub struct MatchedItem {
66 pub item: Arc<dyn SkimItem>,
67 pub rank: Rank,
68 pub matched_range: Option<MatchRange>, pub item_idx: u32,
70}
71
72impl MatchedItem {}
73
74use std::cmp::Ordering as CmpOrd;
75
76impl PartialEq for MatchedItem {
77 fn eq(&self, other: &Self) -> bool {
78 self.rank.eq(&other.rank)
79 }
80}
81
82impl std::cmp::Eq for MatchedItem {}
83
84impl PartialOrd for MatchedItem {
85 fn partial_cmp(&self, other: &Self) -> Option<CmpOrd> {
86 Some(self.rank.cmp(&other.rank))
87 }
88}
89
90impl Ord for MatchedItem {
91 fn cmp(&self, other: &Self) -> CmpOrd {
92 self.rank.cmp(&other.rank)
93 }
94}
95
96const ITEM_POOL_CAPACITY: usize = 1024;
98
99pub struct ItemPool {
100 length: AtomicUsize,
101 pool: SpinLock<Vec<Arc<dyn SkimItem>>>,
102 taken: AtomicUsize,
104
105 reserved_items: SpinLock<Vec<Arc<dyn SkimItem>>>,
107 lines_to_reserve: usize,
108}
109
110impl Default for ItemPool {
111 fn default() -> Self {
112 Self::new()
113 }
114}
115
116impl ItemPool {
117 pub fn new() -> Self {
118 Self {
119 length: AtomicUsize::new(0),
120 pool: SpinLock::new(Vec::with_capacity(ITEM_POOL_CAPACITY)),
121 taken: AtomicUsize::new(0),
122 reserved_items: SpinLock::new(Vec::new()),
123 lines_to_reserve: 0,
124 }
125 }
126
127 pub fn lines_to_reserve(mut self, lines_to_reserve: usize) -> Self {
128 self.lines_to_reserve = lines_to_reserve;
129 self
130 }
131
132 pub fn len(&self) -> usize {
133 self.length.load(Ordering::SeqCst)
134 }
135
136 pub fn is_empty(&self) -> bool {
137 self.len() == 0
138 }
139
140 pub fn num_not_taken(&self) -> usize {
141 self.length.load(Ordering::SeqCst) - self.taken.load(Ordering::SeqCst)
142 }
143
144 pub fn num_taken(&self) -> usize {
145 self.taken.load(Ordering::SeqCst)
146 }
147
148 pub fn clear(&self) {
149 let mut items = self.pool.lock();
150 items.clear();
151 let mut header_items = self.reserved_items.lock();
152 header_items.clear();
153 self.taken.store(0, Ordering::SeqCst);
154 self.length.store(0, Ordering::SeqCst);
155 }
156
157 pub fn reset(&self) {
158 let _items = self.pool.lock();
160 self.taken.store(0, Ordering::SeqCst);
161 }
162
163 pub fn append(&self, mut items: Vec<Arc<dyn SkimItem>>) -> usize {
165 let len = items.len();
166 trace!("item pool, append {} items", len);
167 let mut pool = self.pool.lock();
168 let mut header_items = self.reserved_items.lock();
169
170 let to_reserve = self.lines_to_reserve - header_items.len();
171 if to_reserve > 0 {
172 let to_reserve = min(to_reserve, items.len());
173 header_items.extend_from_slice(&items[..to_reserve]);
174 pool.extend_from_slice(&items[to_reserve..]);
175 } else {
176 pool.append(&mut items);
177 }
178 self.length.store(pool.len(), Ordering::SeqCst);
179 trace!("item pool, done append {} items", len);
180 pool.len()
181 }
182
183 pub fn take(&self) -> ItemPoolGuard<Arc<dyn SkimItem>> {
184 let guard = self.pool.lock();
185 let taken = self.taken.swap(guard.len(), Ordering::SeqCst);
186 ItemPoolGuard { guard, start: taken }
187 }
188
189 pub fn reserved(&self) -> ItemPoolGuard<Arc<dyn SkimItem>> {
190 let guard = self.reserved_items.lock();
191 ItemPoolGuard { guard, start: 0 }
192 }
193}
194
195pub struct ItemPoolGuard<'a, T: Sized + 'a> {
196 guard: SpinLockGuard<'a, Vec<T>>,
197 start: usize,
198}
199
200impl<'mutex, T: Sized> Deref for ItemPoolGuard<'mutex, T> {
201 type Target = [T];
202
203 fn deref(&self) -> &[T] {
204 &self.guard[self.start..]
205 }
206}
207
208#[derive(Debug, PartialEq, Eq, Clone, Copy)]
210pub enum RankCriteria {
211 Score,
212 Begin,
213 End,
214 NegScore,
215 NegBegin,
216 NegEnd,
217 Length,
218 NegLength,
219}
220
221impl clap::ValueEnum for RankCriteria {
222 fn value_variants<'a>() -> &'a [Self] {
223 &[
224 Self::Score,
225 Self::Begin,
226 Self::End,
227 Self::NegScore,
228 Self::NegBegin,
229 Self::NegEnd,
230 Self::Length,
231 Self::NegLength,
232 ]
233 }
234
235 fn to_possible_value(&self) -> Option<clap::builder::PossibleValue> {
236 match self {
237 RankCriteria::Score => Some(clap::builder::PossibleValue::new("score")),
238 RankCriteria::Begin => Some(clap::builder::PossibleValue::new("begin")),
239 RankCriteria::End => Some(clap::builder::PossibleValue::new("end")),
240 RankCriteria::NegScore => Some(clap::builder::PossibleValue::new("-score")),
241 RankCriteria::NegBegin => Some(clap::builder::PossibleValue::new("-begin")),
242 RankCriteria::NegEnd => Some(clap::builder::PossibleValue::new("-end")),
243 RankCriteria::Length => Some(clap::builder::PossibleValue::new("length")),
244 RankCriteria::NegLength => Some(clap::builder::PossibleValue::new("-length")),
245 }
246 }
247}
248
249pub fn parse_criteria(text: &str) -> Option<RankCriteria> {
250 match text.to_lowercase().as_ref() {
251 "score" => Some(RankCriteria::Score),
252 "begin" => Some(RankCriteria::Begin),
253 "end" => Some(RankCriteria::End),
254 "-score" => Some(RankCriteria::NegScore),
255 "-begin" => Some(RankCriteria::NegBegin),
256 "-end" => Some(RankCriteria::NegEnd),
257 "length" => Some(RankCriteria::Length),
258 "-length" => Some(RankCriteria::NegLength),
259 _ => None,
260 }
261}