nucleo_picker/injector.rs
1use std::sync::Arc;
2
3use nucleo as nc;
4
5use super::Render;
6
7/// A handle which allows adding new items to a [`Picker`](super::Picker).
8///
9/// This struct is cheaply clonable and can be sent across threads. By default, add new items to
10/// the [`Picker`](super::Picker) using the [`push`](Injector::push) method. For convenience, an
11/// injector also implements [`Extend`] if you want to add items from an iterator.
12///
13/// ## `DeserializeSeed` implementation
14/// If your items are being read from an external source and deserialized within the
15/// [`serde`](::serde) framework, you may find it convenient to enable the `serde` optional feature.
16/// With this feature enabled, an injector implements
17/// [`DeserializeSeed`](::serde::de::DeserializeSeed) and expects a sequence of picker items.
18/// The [`DeserializeSeed`](::serde::de::DeserializeSeed) implementation sends the items to the
19/// picker immediately, without waiting for the entire file to be deserialized (or even loaded into
20/// memory).
21/// ```
22/// # #[cfg(not(feature = "serde"))]
23/// # fn main() {}
24/// # #[cfg(feature = "serde")]
25/// # fn main() {
26/// use nucleo_picker::{render::StrRenderer, Picker, Render};
27/// use serde::{de::DeserializeSeed, Deserialize};
28/// use serde_json::Deserializer;
29///
30/// let input = r#"
31/// [
32/// "Alvar Aalto",
33/// "Frank Lloyd Wright",
34/// "Zaha Hadid",
35/// "Le Corbusier"
36/// ]
37/// "#;
38///
39/// // the type annotation here also tells `serde_json` to deserialize `input` as a sequence of
40/// // `String`.
41/// let mut picker: Picker<String, _> = Picker::new(StrRenderer);
42/// let injector = picker.injector();
43///
44/// // in practice, you would read from a file or a socket and use
45/// // `Deserializer::from_reader` instead, and run this in a separate thread
46/// injector
47/// .deserialize(&mut Deserializer::from_str(input))
48/// .unwrap();
49/// # }
50/// ```
51pub struct Injector<T, R> {
52 inner: nc::Injector<T>,
53 render: Arc<R>,
54}
55
56impl<T, R> Clone for Injector<T, R> {
57 fn clone(&self) -> Self {
58 Self {
59 inner: self.inner.clone(),
60 render: self.render.clone(),
61 }
62 }
63}
64
65impl<T: Send + Sync + 'static, R: Render<T>> Injector<T, R> {
66 pub(crate) fn new(inner: nc::Injector<T>, render: Arc<R>) -> Self {
67 Self { inner, render }
68 }
69}
70
71impl<T, R: Render<T>> Injector<T, R> {
72 /// Add an item to the picker.
73 pub fn push(&self, item: T) {
74 self.inner.push(item, |s, columns| {
75 columns[0] = self.render.render(s).as_ref().into();
76 });
77 }
78
79 /// Add items from an iterator to the picker, when the number of items in the iterator is known exactly.
80 ///
81 /// This can result in more efficient insertion when inserting a large number of elements in
82 /// a single batch.
83 pub fn extend_exact<I>(&self, iter: I)
84 where
85 I: IntoIterator<Item = T>,
86 <I as IntoIterator>::IntoIter: ExactSizeIterator,
87 {
88 self.inner.extend_exact(iter, |s, columns| {
89 columns[0] = self.render.render(s).as_ref().into();
90 });
91 }
92
93 /// Returns a reference to the renderer internal to the picker.
94 pub fn renderer(&self) -> &R {
95 &self.render
96 }
97}
98
99impl<T, R: Render<T>> Extend<T> for Injector<T, R> {
100 fn extend<I: IntoIterator<Item = T>>(&mut self, iter: I) {
101 for it in iter {
102 self.push(it);
103 }
104 }
105}
106
107#[cfg(feature = "serde")]
108mod serde {
109 use serde::{
110 Deserialize,
111 de::{DeserializeSeed, Deserializer, SeqAccess, Visitor},
112 };
113
114 use super::Injector;
115 use crate::Render;
116
117 #[cfg_attr(docsrs, doc(cfg(feature = "serde")))]
118 impl<'de, T, R> Visitor<'de> for &Injector<T, R>
119 where
120 T: Send + Sync + 'static + Deserialize<'de>,
121 R: Render<T>,
122 {
123 type Value = ();
124
125 fn expecting(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
126 f.write_str("a sequence of picker items")
127 }
128
129 fn visit_seq<S>(self, mut seq: S) -> Result<(), S::Error>
130 where
131 S: SeqAccess<'de>,
132 {
133 while let Some(item) = seq.next_element()? {
134 self.push(item);
135 }
136
137 Ok(())
138 }
139 }
140
141 #[cfg_attr(docsrs, doc(cfg(feature = "serde")))]
142 impl<'de, T, R> DeserializeSeed<'de> for &Injector<T, R>
143 where
144 T: Send + Sync + 'static + Deserialize<'de>,
145 R: Render<T>,
146 {
147 type Value = ();
148
149 /// Deserialize from a sequence of picker items.
150 /// This implementation is enabled using the `serde` feature.
151 fn deserialize<D>(self, deserializer: D) -> Result<Self::Value, D::Error>
152 where
153 D: Deserializer<'de>,
154 {
155 deserializer.deserialize_seq(self)
156 }
157 }
158}