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