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}