relm4/factory/sync/collections/
hashmap.rs1use crate::{Receiver, Sender};
2
3use crate::factory::sync::builder::FactoryBuilder;
4use crate::factory::sync::handle::FactoryHandle;
5use crate::factory::{CloneableFactoryComponent, FactoryComponent, FactoryView};
6
7use std::collections::HashMap;
8use std::collections::hash_map::RandomState;
9use std::hash::{BuildHasher, Hash, Hasher};
10use std::iter::FusedIterator;
11use std::marker::PhantomData;
12use std::ops;
13
14use gtk::prelude::IsA;
15
16#[derive(Debug)]
17#[must_use]
18pub struct FactoryElementGuard<'a, C>
19where
20 C: FactoryComponent,
21{
22 inner: &'a mut FactoryHandle<C>,
23}
24
25impl<C> ops::Deref for FactoryElementGuard<'_, C>
26where
27 C: FactoryComponent,
28{
29 type Target = C;
30
31 fn deref(&self) -> &Self::Target {
32 self.inner.data.get()
33 }
34}
35
36impl<C> ops::DerefMut for FactoryElementGuard<'_, C>
37where
38 C: FactoryComponent,
39{
40 fn deref_mut(&mut self) -> &mut Self::Target {
41 self.inner.data.get_mut()
42 }
43}
44
45impl<C> Drop for FactoryElementGuard<'_, C>
46where
47 C: FactoryComponent,
48{
49 fn drop(&mut self) {
50 self.inner.notifier.send(()).unwrap()
51 }
52}
53
54#[derive(Debug)]
55pub struct FactoryHashMapBuilder<K, C: FactoryComponent, S = RandomState> {
57 hasher: S,
58 component: PhantomData<C>,
59 key: PhantomData<K>,
60}
61
62impl<K, C> Default for FactoryHashMapBuilder<K, C>
63where
64 C: FactoryComponent,
65{
66 fn default() -> Self {
67 Self::new()
68 }
69}
70
71impl<K, C> FactoryHashMapBuilder<K, C>
72where
73 C: FactoryComponent,
74 C::ParentWidget: Default,
75{
76 #[must_use]
77 pub fn launch_default(self) -> FactoryHashMapConnector<K, C> {
79 self.launch(Default::default())
80 }
81}
82
83impl<K, C> FactoryHashMapBuilder<K, C>
84where
85 C: FactoryComponent,
86{
87 #[must_use]
89 pub fn new() -> Self {
90 Self {
91 hasher: RandomState::default(),
92 component: PhantomData,
93 key: PhantomData,
94 }
95 }
96
97 pub fn hasher<H: Hasher>(self, hasher: H) -> FactoryHashMapBuilder<K, C, H> {
99 let Self { component, key, .. } = self;
100
101 FactoryHashMapBuilder {
102 hasher,
103 component,
104 key,
105 }
106 }
107
108 pub fn launch(self, widget: C::ParentWidget) -> FactoryHashMapConnector<K, C> {
111 let Self { hasher, key, .. } = self;
112
113 let (output_sender, output_receiver) = crate::channel();
114
115 FactoryHashMapConnector {
116 widget,
117 output_sender,
118 output_receiver,
119 hasher,
120 _key: key,
121 }
122 }
123}
124
125#[derive(Debug)]
126pub struct FactoryHashMapConnector<K, C, S = RandomState>
128where
129 C: FactoryComponent,
130{
131 widget: C::ParentWidget,
132 output_sender: Sender<C::Output>,
133 output_receiver: Receiver<C::Output>,
134 hasher: S,
135 _key: PhantomData<K>,
136}
137
138impl<K, C> FactoryHashMapConnector<K, C>
139where
140 C: FactoryComponent,
141{
142 pub fn forward<F, Msg>(self, sender_: &Sender<Msg>, f: F) -> FactoryHashMap<K, C>
144 where
145 F: Fn(C::Output) -> Msg + Send + 'static,
146 C::Output: Send,
147 Msg: Send + 'static,
148 {
149 let Self {
150 widget,
151 output_sender,
152 output_receiver,
153 hasher,
154 ..
155 } = self;
156
157 let sender_clone = sender_.clone();
158
159 crate::spawn(async move {
160 while let Some(msg) = output_receiver.recv().await {
161 if sender_clone.send(f(msg)).is_err() {
162 break;
163 }
164 }
165 });
166
167 FactoryHashMap {
168 widget,
169 output_sender,
170 inner: HashMap::with_hasher(hasher),
171 }
172 }
173
174 pub fn detach(self) -> FactoryHashMap<K, C> {
176 let Self {
177 widget,
178 output_sender,
179 hasher,
180 ..
181 } = self;
182
183 FactoryHashMap {
184 widget,
185 output_sender,
186 inner: HashMap::with_hasher(hasher),
187 }
188 }
189}
190
191#[derive(Debug)]
194pub struct FactoryHashMap<K, C: FactoryComponent, S = RandomState> {
195 widget: C::ParentWidget,
196 output_sender: Sender<C::Output>,
197 inner: HashMap<K, FactoryHandle<C>, S>,
198}
199
200impl<K, C, S> Drop for FactoryHashMap<K, C, S>
201where
202 C: FactoryComponent,
203{
204 fn drop(&mut self) {
205 self.clear();
206 }
207}
208
209impl<K, C, S> ops::Index<&K> for FactoryHashMap<K, C, S>
210where
211 C: FactoryComponent<Index = K>,
212 K: Hash + Eq,
213 S: BuildHasher,
214{
215 type Output = C;
216
217 fn index(&self, key: &K) -> &Self::Output {
218 self.get(key).expect("Called `get` on an invalid key")
219 }
220}
221
222impl<K, C> FactoryHashMap<K, C, RandomState>
223where
224 C: FactoryComponent,
225{
226 #[must_use]
228 pub fn builder() -> FactoryHashMapBuilder<K, C> {
229 FactoryHashMapBuilder::new()
230 }
231}
232
233impl<K, C, S> FactoryHashMap<K, C, S>
234where
235 C: FactoryComponent,
236{
237 pub fn len(&self) -> usize {
239 self.inner.len()
240 }
241
242 pub fn is_empty(&self) -> bool {
244 self.inner.is_empty()
245 }
246
247 pub fn broadcast(&self, msg: C::Input)
249 where
250 C::Input: Clone,
251 {
252 self.inner.values().for_each(|c| c.input.emit(msg.clone()));
253 }
254
255 pub const fn widget(&self) -> &C::ParentWidget {
257 &self.widget
258 }
259
260 pub fn iter(&self) -> impl ExactSizeIterator<Item = (&K, &C)> + FusedIterator {
262 self.inner.iter().map(|(k, c)| (k, c.data.get()))
263 }
264
265 pub fn values(&self) -> impl ExactSizeIterator<Item = &C> + FusedIterator {
267 self.inner.values().map(|c| c.data.get())
268 }
269
270 pub fn keys(&self) -> impl ExactSizeIterator<Item = &K> + FusedIterator {
272 self.inner.keys()
273 }
274
275 pub fn clear(&mut self) {
277 for (_, handle) in self.inner.drain() {
278 self.widget.factory_remove(&handle.returned_widget);
279 }
280 }
281}
282
283impl<K, C> FactoryHashMap<K, C, RandomState>
284where
285 C: FactoryComponent<Index = K>,
286 K: Hash + Eq,
287{
288 pub fn from_vec(component_vec: Vec<(K, C::Init)>, widget: C::ParentWidget) -> Self {
290 let mut output = Self::builder().launch(widget).detach();
291 for (key, init) in component_vec {
292 output.insert(key, init);
293 }
294 output
295 }
296}
297
298impl<K, C, S> FactoryHashMap<K, C, S>
299where
300 C: FactoryComponent<Index = K>,
301 K: Hash + Eq,
302 S: BuildHasher,
303{
304 pub fn send(&self, key: &K, msg: C::Input) {
306 self.inner[key].input.emit(msg);
307 }
308
309 pub fn get(&self, key: &K) -> Option<&C> {
314 self.inner.get(key).map(|c| c.data.get())
315 }
316
317 pub fn get_mut(&mut self, key: &K) -> Option<FactoryElementGuard<'_, C>> {
322 self.inner
323 .get_mut(key)
324 .map(|c| FactoryElementGuard { inner: c })
325 }
326
327 pub fn insert(&mut self, key: K, init: C::Init) -> Option<C> {
334 let existing = self.remove(&key);
335
336 let builder = FactoryBuilder::new(&key, init, self.output_sender.clone());
337
338 let position = C::position(&builder.data, &key);
339 let returned_widget = self
340 .widget
341 .factory_append(builder.root_widget.clone(), &position);
342
343 let component = builder.launch(&key, returned_widget);
344
345 assert!(self.inner.insert(key, component).is_none());
346
347 existing
348 }
349
350 pub fn remove(&mut self, key: &K) -> Option<C> {
352 if let Some(handle) = self.inner.remove(key) {
353 self.widget.factory_remove(&handle.returned_widget);
354 Some(handle.data.into_inner())
355 } else {
356 None
357 }
358 }
359}
360
361impl<K, C> Clone for FactoryHashMap<K, C, RandomState>
363where
364 C: CloneableFactoryComponent,
365 K: Clone + Hash + Eq,
366 C: FactoryComponent<Index = K>,
367{
368 fn clone(&self) -> Self {
369 let mut clone = FactoryHashMap::builder()
371 .launch(self.widget.clone())
372 .detach();
373 for (k, item) in self.iter() {
375 let init = C::get_init(item);
377 clone.insert(k.clone(), init);
378 }
379 clone
381 }
382}
383
384impl<K, C> FactoryHashMap<K, C, RandomState>
385where
386 C: FactoryComponent,
387 K: Clone + Hash + Eq,
388 C::ParentWidget: IsA<gtk::Stack>,
389 C::Root: IsA<gtk::Widget>,
390{
391 pub fn set_visible(&self, key: &K) -> bool {
394 if let Some(handle) = self.inner.get(key) {
395 self.widget
396 .as_ref()
397 .set_visible_child(handle.root_widget.as_ref());
398 true
399 } else {
400 false
401 }
402 }
403}