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