matchmaker/nucleo/
injector.rs

1// Original code from https://github.com/helix-editor/helix (MPL 2.0)
2// Modified by Squirreljetpack, 2025
3
4use std::{
5    marker::PhantomData, sync::{
6        Arc,
7        atomic::{AtomicU32, Ordering},
8    }
9};
10
11use super::worker::{Column, Worker, WorkerError};
12use super::{Indexed, Segmented};
13use crate::{SSS, SegmentableItem, SplitterFn};
14
15pub trait Injector: Clone {
16    type InputItem;
17    type Inner: Injector;
18    type Context;
19
20    fn new(injector: Self::Inner, data: Self::Context) -> Self;
21    fn inner(&self) -> &Self::Inner;
22    fn wrap(
23        &self,
24        item: Self::InputItem,
25    ) -> Result<<Self::Inner as Injector>::InputItem, WorkerError>;
26
27    fn push(&self, item: Self::InputItem) -> Result<(), WorkerError> {
28        let item = self.wrap(item)?;
29        self.inner().push(item)
30    }
31}
32
33impl Injector for () {
34    fn inner(&self) -> &Self::Inner {
35        unreachable!()
36    }
37    fn new(_: Self::Inner, _: Self::Context) -> Self {
38        unreachable!()
39    }
40    fn wrap(
41        &self,
42        _: Self::InputItem,
43    ) -> Result<<Self::Inner as Injector>::InputItem, WorkerError> {
44        unreachable!()
45    }
46
47    type Context = ();
48    type Inner = ();
49    type InputItem = ();
50}
51
52pub struct WorkerInjector<T> {
53    pub(super) inner: nucleo::Injector<T>,
54    pub(super) columns: Arc<[Column<T>]>,
55    pub(super) version: u32,
56    pub(super) picker_version: Arc<AtomicU32>,
57}
58
59
60
61impl<T: SSS> Injector for WorkerInjector<T> {
62    type InputItem = T;
63    type Inner = ();
64    type Context = Worker<T>;
65
66    fn new(_: Self::Inner, data: Self::Context) -> Self {
67        data.injector()
68    }
69
70    fn inner(&self) -> &Self::Inner {
71        &()
72    }
73
74    fn wrap(
75        &self,
76        _: Self::InputItem,
77    ) -> Result<<Self::Inner as Injector>::InputItem, WorkerError> {
78        Ok(())
79    }
80
81    fn push(&self, item: T) -> Result<(), WorkerError> {
82        if self.version != self.picker_version.load(Ordering::Relaxed) {
83            return Err(WorkerError::InjectorShutdown);
84        }
85        push_impl(&self.inner, &self.columns, item);
86        Ok(())
87    }
88}
89
90pub(super) fn push_impl<T>(injector: &nucleo::Injector<T>, columns: &[Column<T>], item: T) {
91    injector.push(item, |item, dst| {
92        for (column, text) in columns.iter().filter(|column| column.filter).zip(dst) {
93            *text = column.format_text(item).into()
94        }
95    });
96}
97
98// ----- Injectors
99
100pub struct IndexedInjector<T, I: Injector<InputItem = Indexed<T>>> {
101    injector: I,
102    count: Arc<AtomicU32>,
103    input_type: PhantomData<T>,
104}
105
106impl<T, I: Injector<InputItem = Indexed<T>>> Injector for IndexedInjector<T, I> {
107    type InputItem = T;
108    type Inner = I;
109    type Context = u32;
110
111    fn new(injector: Self::Inner, count: Self::Context) -> Self {
112        Self {
113            injector,
114            count: Arc::new(AtomicU32::new(count)),
115            input_type: PhantomData,
116        }
117    }
118
119    fn wrap(
120        &self,
121        item: Self::InputItem,
122    ) -> Result<<Self::Inner as Injector>::InputItem, WorkerError> {
123        let index = self.count.fetch_add(1, Ordering::Relaxed);
124        Ok(Indexed { index, inner: item })
125    }
126
127    fn inner(&self) -> &Self::Inner {
128        &self.injector
129    }
130}
131
132
133pub struct SegmentedInjector<T: SegmentableItem, I: Injector<InputItem = Segmented<T>>> {
134    injector: I,
135    splitter: SplitterFn<T>,
136    input_type: PhantomData<T>,
137}
138
139impl<T: SegmentableItem, I: Injector<InputItem = Segmented<T>>> Injector
140    for SegmentedInjector<T, I>
141{
142    type InputItem = T;
143    type Inner = I;
144    type Context = SplitterFn<T>;
145
146    fn new(injector: Self::Inner, data: Self::Context) -> Self {
147        Self {
148            injector,
149            splitter: data,
150            input_type: PhantomData,
151        }
152    }
153
154    fn wrap(
155        &self,
156        item: Self::InputItem,
157    ) -> Result<<Self::Inner as Injector>::InputItem, WorkerError> {
158        let ranges = (self.splitter)(&item);
159        Ok(Segmented {
160            inner: item,
161            ranges,
162        })
163    }
164
165    fn inner(&self) -> &Self::Inner {
166        &self.injector
167    }
168
169    fn push(&self, item: Self::InputItem) -> Result<(), WorkerError> {
170        let item = self.wrap(item)?;
171        self.inner().push(item)
172    }
173}
174
175// pub type SeenMap<T> = Arc<std::sync::Mutex<collections::HashSet<T>>>;
176// #[derive(Clone)]
177// pub struct UniqueInjector<T, I: Injector<InputItem = T>> {
178//     injector: I,
179//     seen: SeenMap<T>,
180// }
181// impl<T, I> Injector for UniqueInjector<T, I>
182// where
183//     T: Eq + std::hash::Hash + Clone,
184//     I: Injector<InputItem = T>,
185// {
186//     type InputItem = T;
187//     type Inner = I;
188//     type Context = SeenMap<T>;
189
190//     fn new(injector: Self::Inner, _ctx: Self::Context) -> Self {
191//         Self {
192//             injector,
193//             seen: _ctx,
194//         }
195//     }
196
197//     fn wrap(&self, item: Self::InputItem) -> Result<<Self::Inner as Injector>::InputItem, WorkerError> {
198//         let mut seen = self.seen.lock().unwrap();
199//         if seen.insert(item.clone()) {
200//             Ok(item)
201//         } else {
202//             Err(WorkerError::Custom("Duplicate"))
203//         }
204//     }
205
206//     fn inner(&self) -> &Self::Inner {
207//         &self.injector
208//     }
209// }
210
211
212// ----------- CLONE ----------------------------
213impl<T> Clone for WorkerInjector<T> {
214    fn clone(&self) -> Self {
215        Self {
216            inner: self.inner.clone(),
217            columns: Arc::clone(&self.columns),
218            version: self.version,
219            picker_version: Arc::clone(&self.picker_version),
220        }
221    }
222}
223
224impl<T, I: Injector<InputItem = Indexed<T>>> Clone for IndexedInjector<T, I> {
225    fn clone(&self) -> Self {
226        Self {
227            injector: self.injector.clone(),
228            count: Arc::clone(&self.count),
229            input_type: PhantomData,
230        }
231    }
232}
233
234impl<T: SegmentableItem, I: Injector<InputItem = Segmented<T>>> Clone for SegmentedInjector<T, I> {
235    fn clone(&self) -> Self {
236        Self {
237            injector: self.injector.clone(),
238            splitter: Arc::clone(&self.splitter),
239            input_type: PhantomData,
240        }
241    }
242}