Skip to main content

matchmaker/
selector.rs

1use crate::nucleo::Indexed;
2use crate::{Identifier, Selection};
3use indexmap::IndexMap;
4use rustc_hash::FxBuildHasher;
5use std::sync::Mutex;
6use std::{borrow::Borrow, hash::Hash, sync::Arc};
7
8pub type SelectionValidator<S> = fn(&S) -> bool;
9
10#[derive(Debug)]
11pub struct Selector<T, S> {
12    selections: Option<SelectorImpl<u32, S>>,
13    pub identifier: Identifier<T, S>,
14    pub validator: SelectionValidator<S>,
15}
16
17pub fn truthy_validator<S>(_: &S) -> bool {
18    true
19}
20
21impl<T> Selector<Indexed<T>, ()> {
22    /// See [`Indexed::dummy_identifier`].
23    pub fn new_disabled() -> Self {
24        Self {
25            selections: None,
26            identifier: Indexed::dummy_identifier,
27            validator: truthy_validator,
28        }
29    }
30}
31
32impl<T, S: Selection> Selector<T, S> {
33    pub fn new(identifier: Identifier<T, S>) -> Self {
34        Self {
35            selections: Some(SelectorImpl::new()),
36            identifier,
37            validator: truthy_validator,
38        }
39    }
40
41    pub fn with_validator(mut self, validator: SelectionValidator<S>) -> Self {
42        self.validator = validator;
43        self
44    }
45
46    pub fn disabled(mut self) -> Self {
47        self.selections = None;
48        self
49    }
50
51    pub fn is_disabled(&self) -> bool {
52        self.selections.is_none()
53    }
54
55    pub fn id(&self, item: &T) -> u32 {
56        (self.identifier)(item).0
57    }
58    pub fn eval(&self, item: &T) -> S {
59        (self.identifier)(item).1
60    }
61
62    // --------------------------------------------
63
64    pub fn sel(&mut self, item: &T) -> bool {
65        let Some(selections) = &mut self.selections else {
66            return false;
67        };
68
69        let (k, v) = (self.identifier)(item);
70        selections.insert(k, v)
71    }
72
73    pub fn desel(&mut self, item: &T) -> bool {
74        let Some(selections) = &mut self.selections else {
75            return false;
76        };
77
78        let (k, _v) = (self.identifier)(item);
79        selections.remove(&k)
80    }
81
82    pub fn contains(&self, item: &T) -> bool {
83        let Some(selections) = &self.selections else {
84            return false;
85        };
86
87        let (k, _v) = (self.identifier)(item);
88        selections.contains(&k)
89    }
90
91    pub fn toggle(&mut self, item: &T) {
92        let Some(selections) = &mut self.selections else {
93            return;
94        };
95
96        let (k, v) = (self.identifier)(item);
97        if selections.contains(&k) {
98            selections.remove(&k);
99        } else {
100            selections.insert(k, v);
101        }
102    }
103
104    pub fn clear(&mut self) {
105        if let Some(selections) = &mut self.selections {
106            selections.clear();
107        }
108    }
109
110    pub fn len(&self) -> usize {
111        self.selections.as_ref().map_or(0, |s| s.len())
112    }
113
114    // -----------------------------------------------------
115
116    pub fn is_empty(&self) -> bool {
117        self.selections.as_ref().is_none_or(|s| s.is_empty())
118    }
119
120    pub fn output(&mut self) -> impl Iterator<Item = S> {
121        if let Some(selections) = &mut self.selections {
122            let mut set = selections.set.lock().unwrap();
123            std::mem::take(&mut *set).into_values()
124        } else {
125            IndexMap::with_capacity(0).into_values()
126        }
127    }
128
129    pub fn identify_to_vec<I>(&self, items: I) -> Vec<S>
130    where
131        I: IntoIterator,
132        I::Item: std::borrow::Borrow<T> + Send,
133    {
134        items
135            .into_iter()
136            .map(|item| (self.identifier)(item.borrow()).1)
137            .collect()
138    }
139
140    pub fn map_to_vec<U, F>(&self, f: F) -> Vec<U>
141    where
142        F: FnMut(&S) -> U,
143    {
144        self.selections
145            .as_ref()
146            .map_or_else(Vec::new, |s| s.map_to_vec(f))
147    }
148
149    pub fn map_last<U, F>(&self, f: F) -> Option<U>
150    where
151        F: FnOnce(&S) -> U,
152    {
153        self.selections
154            .as_ref()
155            .and_then(|s| s.map_last(|(_, s)| f(s)))
156    }
157
158    pub fn revalidate(&mut self) {
159        let Some(selections) = &mut self.selections else {
160            return;
161        };
162
163        let mut set = selections.set.lock().unwrap();
164        let validator = &self.validator;
165
166        set.retain(|_, v| validator(v));
167    }
168
169    pub fn cycle_all_bg<I>(&self, items: I)
170    where
171        I: IntoIterator,
172        I::Item: std::borrow::Borrow<T> + Send,
173    {
174        let Some(selections) = &self.selections else {
175            return;
176        };
177
178        let results: Vec<_> = items
179            .into_iter()
180            .map(|item| (self.identifier)(item.borrow()))
181            .collect();
182
183        let selections = selections.clone();
184
185        #[cfg(feature = "parallelism")]
186        tokio::task::spawn_blocking(move || {
187            let mut set_guard = selections.set.lock().unwrap();
188
189            let mut all = true;
190            let mut seen = 0;
191            for (i, (k, _)) in results.iter().enumerate() {
192                if !set_guard.contains_key(k) {
193                    all = false;
194                    seen = i;
195                    break;
196                }
197            }
198
199            if all {
200                for (k, _) in results {
201                    set_guard.swap_remove(&k);
202                }
203            } else {
204                for (k, v) in results.into_iter().skip(seen) {
205                    set_guard.insert(k, v);
206                }
207            }
208        });
209
210        #[cfg(not(feature = "parallelism"))]
211        {
212            let mut set_guard = selections.set.lock().unwrap();
213
214            let mut all = true;
215            let mut seen = 0;
216            for (i, (k, _)) in results.iter().enumerate() {
217                if !set_guard.contains_key(k) {
218                    all = false;
219                    seen = i;
220                    break;
221                }
222            }
223
224            if all {
225                for (k, _) in results {
226                    set_guard.swap_remove(&k);
227                }
228            } else {
229                for (k, v) in results.into_iter().skip(seen) {
230                    set_guard.insert(k, v);
231                }
232            }
233        }
234    }
235
236    // ---------- wrappers (?) -----------
237
238    // pub fn insert(&mut self, (k, v): (u32, S)) -> bool {
239    //     let Some(selections) = &mut self.selections else {
240    //         return false;
241    //     };
242    //     selections.insert(k, v)
243    // }
244}
245
246// ---------- Selection Set ---------------
247#[derive(Debug, Clone)]
248struct SelectorImpl<K: Eq + Hash, S> {
249    pub set: Arc<Mutex<IndexMap<K, S, FxBuildHasher>>>,
250}
251
252impl<K: Eq + Hash, S> SelectorImpl<K, S>
253where
254    S: Selection,
255{
256    pub fn new() -> Self {
257        Self {
258            set: Arc::new(Mutex::new(IndexMap::with_hasher(FxBuildHasher))),
259        }
260    }
261
262    pub fn insert(&self, key: K, value: S) -> bool {
263        let mut set = self.set.lock().unwrap();
264        set.insert(key, value).is_none()
265    }
266
267    pub fn remove(&self, key: &K) -> bool {
268        let mut set = self.set.lock().unwrap();
269        set.shift_remove(key).is_some()
270    }
271
272    pub fn contains(&self, key: &K) -> bool {
273        let set = self.set.lock().unwrap();
274        set.contains_key(key)
275    }
276
277    pub fn clear(&self) {
278        let mut set = self.set.lock().unwrap();
279        set.clear();
280    }
281
282    pub fn clone(&self) -> Self {
283        Self {
284            set: Arc::clone(&self.set),
285        }
286    }
287
288    pub fn len(&self) -> usize {
289        let set = self.set.lock().unwrap();
290        set.len()
291    }
292
293    pub fn is_empty(&self) -> bool {
294        let set = self.set.lock().unwrap();
295        set.is_empty()
296    }
297
298    pub fn map_to_vec<U, F>(&self, f: F) -> Vec<U>
299    where
300        F: FnMut(&S) -> U,
301    {
302        let set = self.set.lock().unwrap();
303        set.values().map(f).collect()
304    }
305
306    pub fn map_last<U>(&self, f: impl FnOnce((&K, &S)) -> U) -> Option<U> {
307        let set = self.set.lock().unwrap();
308        set.last().map(f)
309    }
310}