relm4/factory/async/collections/
vec_deque.rs

1use crate::{Receiver, Sender};
2
3use crate::factory::r#async::AsyncFactoryBuilder;
4use crate::factory::r#async::component_storage::AsyncComponentStorage;
5use crate::factory::r#async::traits::AsyncFactoryComponent;
6use crate::factory::{DynamicIndex, FactoryView};
7
8use super::{ModelStateValue, RenderedState};
9
10use std::collections::VecDeque;
11use std::collections::hash_map::DefaultHasher;
12use std::hash::Hash;
13use std::iter::FusedIterator;
14use std::marker::PhantomData;
15use std::ops::Deref;
16
17#[cfg(feature = "libadwaita")]
18use gtk::prelude::Cast;
19
20#[cfg(feature = "libadwaita")]
21use std::hash::Hasher;
22
23/// Provides methods to edit the underlying [`AsyncFactoryVecDeque`].
24///
25/// The changes will be rendered on the widgets after the guard goes out of scope.
26#[derive(Debug)]
27#[must_use]
28pub struct AsyncFactoryVecDequeGuard<'a, C: AsyncFactoryComponent>
29where
30    <C::ParentWidget as FactoryView>::ReturnedWidget: Clone,
31{
32    inner: &'a mut AsyncFactoryVecDeque<C>,
33}
34
35impl<C: AsyncFactoryComponent> Drop for AsyncFactoryVecDequeGuard<'_, C>
36where
37    <C::ParentWidget as FactoryView>::ReturnedWidget: Clone,
38{
39    fn drop(&mut self) {
40        self.inner.render_changes();
41    }
42}
43
44impl<'a, C: AsyncFactoryComponent> AsyncFactoryVecDequeGuard<'a, C>
45where
46    <C::ParentWidget as FactoryView>::ReturnedWidget: Clone,
47{
48    fn new(inner: &'a mut AsyncFactoryVecDeque<C>) -> Self {
49        #[allow(unused_mut)]
50        #[allow(clippy::let_and_return)]
51        let mut guard = AsyncFactoryVecDequeGuard { inner };
52
53        #[cfg(feature = "libadwaita")]
54        guard.apply_external_updates();
55
56        guard
57    }
58
59    /// Drops the guard and renders all changes.
60    ///
61    /// Use this to transfer full ownership back to the [`AsyncFactoryVecDeque`].
62    pub fn drop(self) {
63        drop(self);
64    }
65
66    /// Apply external updates that happened between the last render.
67    ///
68    /// [`AsyncFactoryVecDeque`] should not be edited between calling [`Self::render_changes`]
69    /// and this method, as it might cause undefined behaviour. This shouldn't be possible
70    /// because the method is called in [`FactoryVecDequeGuard::new`].
71    #[cfg(feature = "libadwaita")]
72    fn apply_external_updates(&mut self) {
73        if let Some(tab_view) = self.inner.widget().dynamic_cast_ref::<adw::TabView>() {
74            let length = tab_view.n_pages();
75            let mut hash_values: Vec<u64> = Vec::with_capacity(usize::try_from(length).unwrap());
76
77            for i in 0..length {
78                let page = tab_view.nth_page(i);
79                let mut hasher = DefaultHasher::default();
80                page.hash(&mut hasher);
81                hash_values.push(hasher.finish());
82            }
83
84            // Tab rearrangement
85            for (index, hash) in hash_values.iter().enumerate() {
86                if self
87                    .inner
88                    .rendered_state
89                    .get(index)
90                    .map(|state| state.widget_hash)
91                    == Some(*hash)
92                {
93                    let old_position = self
94                        .inner
95                        .rendered_state
96                        .iter()
97                        .position(|state| state.widget_hash == *hash)
98                        .expect("A new widget was added");
99
100                    let elem = self.inner.rendered_state.remove(old_position).unwrap();
101                    self.inner.rendered_state.insert(index, elem);
102
103                    self.move_to(old_position, index);
104                }
105            }
106
107            // Closed tabs
108            let mut index = 0;
109            while index < self.inner.rendered_state.len() {
110                let hash = self.inner.rendered_state[index].widget_hash;
111                if hash_values.contains(&hash) {
112                    index += 1;
113                } else {
114                    self.inner.rendered_state.remove(index);
115
116                    self.remove(index);
117                }
118            }
119        }
120    }
121
122    /// Tries to get a mutable reference to
123    /// the model of one element.
124    ///
125    /// Returns [`None`] if `index` is invalid or the async [`init_model()`] method
126    /// hasn't returned yet.
127    ///
128    /// [`init_model()`]: AsyncFactoryComponent::init_model
129    pub fn get_mut(&mut self, index: usize) -> Option<&mut C> {
130        // Mark as modified
131        if let Some(state) = self.inner.model_state.get_mut(index) {
132            state.changed = true;
133        }
134        self.inner
135            .components
136            .get_mut(index)
137            .and_then(AsyncComponentStorage::get_mut)
138    }
139
140    /// Provides a mutable reference to the model of the back element.
141    ///
142    ///  Returns [`None`] if the deque is empty or the async [`init_model()`] method
143    /// of the last element hasn't returned yet.
144    ///
145    /// [`init_model()`]: AsyncFactoryComponent::init_model
146    pub fn back_mut(&mut self) -> Option<&mut C> {
147        self.get_mut(self.len().wrapping_sub(1))
148    }
149
150    /// Provides a mutable reference to the model of the front element.
151    ///
152    ///  Returns [`None`] if the deque is empty or the async [`init_model()`] method
153    /// of the first element hasn't returned yet.
154    ///
155    /// [`init_model()`]: AsyncFactoryComponent::init_model
156    pub fn front_mut(&mut self) -> Option<&mut C> {
157        self.get_mut(0)
158    }
159
160    /// Removes the last element from the [`AsyncFactoryVecDeque`] and returns it,
161    /// or [`None`] if it is empty or the async [`init_model()`] method
162    /// of the element hasn't returned yet.
163    ///
164    /// [`init_model()`]: AsyncFactoryComponent::init_model
165    pub fn pop_back(&mut self) -> Option<C> {
166        if self.is_empty() {
167            None
168        } else {
169            self.remove(self.len() - 1)
170        }
171    }
172
173    /// Removes the first element from the [`AsyncFactoryVecDeque`] and returns it,
174    /// or [`None`] if it is empty or the async [`init_model()`] method
175    /// of the element hasn't returned yet.
176    ///
177    /// [`init_model()`]: AsyncFactoryComponent::init_model
178    pub fn pop_front(&mut self) -> Option<C> {
179        self.remove(0)
180    }
181
182    /// Removes and returns the element at index from the [`AsyncFactoryVecDeque`].
183    /// or [`None`] if it is empty or the async [`init_model()`] method
184    /// of the element hasn't returned yet.
185    ///
186    /// Element at index 0 is the front of the queue.
187    ///
188    /// [`init_model()`]: AsyncFactoryComponent::init_model
189    pub fn remove(&mut self, index: usize) -> Option<C> {
190        self.inner.model_state.remove(index);
191        let component = self.inner.components.remove(index);
192
193        // Decrement the indexes of the following elements.
194        for states in self.inner.model_state.iter_mut().skip(index) {
195            states.index.decrement();
196        }
197
198        if let Some(comp) = &component
199            && let Some(widget) = &comp.returned_widget()
200        {
201            self.widget.factory_remove(widget);
202        }
203
204        component.and_then(AsyncComponentStorage::extract)
205    }
206
207    /// Appends an element at the end of the [`AsyncFactoryVecDeque`].
208    pub fn push_back(&mut self, init: C::Init) -> DynamicIndex {
209        let index = self.len();
210        self.insert(index, init)
211    }
212
213    /// Prepends an element to the [`AsyncFactoryVecDeque`].
214    pub fn push_front(&mut self, init: C::Init) -> DynamicIndex {
215        self.insert(0, init)
216    }
217
218    /// Inserts an element at index within the [`AsyncFactoryVecDeque`],
219    /// shifting all elements with indices greater than or equal
220    /// to index towards the back.
221    ///
222    /// Element at index 0 is the front of the queue.
223    ///
224    /// # Panics
225    ///
226    /// Panics if index is greater than [`AsyncFactoryVecDeque`]’s length.
227    pub fn insert(&mut self, index: usize, init: C::Init) -> DynamicIndex {
228        let dyn_index = DynamicIndex::new(index);
229
230        // Increment the indexes of the following elements.
231        for states in self.inner.model_state.iter_mut().skip(index) {
232            states.index.increment();
233        }
234
235        let builder = AsyncFactoryBuilder::new(init, self.output_sender.clone());
236
237        self.inner
238            .components
239            .insert(index, AsyncComponentStorage::Builder(builder));
240        self.inner.model_state.insert(
241            index,
242            ModelStateValue {
243                index: dyn_index.clone(),
244                uid: self.uid_counter,
245                changed: false,
246            },
247        );
248        self.inner.uid_counter += 1;
249
250        dyn_index
251    }
252
253    /// Swaps elements at indices `first` and `second`.
254    ///
255    /// `first` and `second` may be equal.
256    ///
257    /// Element at index 0 is the front of the queue.
258    ///
259    /// # Panics
260    ///
261    /// Panics if either index is out of bounds.
262    pub fn swap(&mut self, first: usize, second: usize) {
263        // Don't update anything if both are equal
264        if first != second {
265            self.inner.model_state.swap(first, second);
266            self.inner.components.swap(first, second);
267
268            // Update indexes.
269            self.model_state[first].index.set_value(first);
270            self.model_state[second].index.set_value(second);
271        }
272    }
273
274    /// Moves an element at index `current_position` to `target`,
275    /// shifting all elements between these positions.
276    ///
277    /// `current_position` and `target` may be equal.
278    ///
279    /// Element at index 0 is the front of the queue.
280    ///
281    /// # Panics
282    ///
283    /// Panics if either index is out of bounds.
284    pub fn move_to(&mut self, current_position: usize, target: usize) {
285        // Don't update anything if both are equal
286        if current_position != target {
287            let elem = self.inner.model_state.remove(current_position).unwrap();
288            // Set new index
289            elem.index.set_value(target);
290            self.inner.model_state.insert(target, elem);
291
292            let comp = self.inner.components.remove(current_position).unwrap();
293            self.inner.components.insert(target, comp);
294
295            // Update indexes.
296            if current_position > target {
297                // Move down -> shift elements in between up.
298                for state in self
299                    .inner
300                    .model_state
301                    .iter_mut()
302                    .skip(target + 1)
303                    .take(current_position - target)
304                {
305                    state.index.increment();
306                }
307            } else {
308                // Move up -> shift elements in between down.
309                for state in self
310                    .inner
311                    .model_state
312                    .iter_mut()
313                    .skip(current_position)
314                    .take(target - current_position)
315                {
316                    state.index.decrement();
317                }
318            }
319        }
320    }
321
322    /// Moves an element at index `current_position` to the front,
323    /// shifting all elements between these positions.
324    ///
325    /// # Panics
326    ///
327    /// Panics if index is out of bounds.
328    pub fn move_front(&mut self, current_position: usize) {
329        self.move_to(current_position, 0);
330    }
331
332    /// Moves an element at index `current_position` to the back,
333    /// shifting all elements between these positions.
334    ///
335    /// # Panics
336    ///
337    /// Panics if index is out of bounds.
338    pub fn move_back(&mut self, current_position: usize) {
339        self.move_to(current_position, self.len() - 1);
340    }
341
342    /// Remove all components from the [`AsyncFactoryVecDeque`].
343    pub fn clear(&mut self) {
344        self.inner.model_state.clear();
345
346        for component in self.inner.components.drain(..) {
347            // Remove all widgets
348            if let Some(widget) = component.returned_widget() {
349                self.inner.widget.factory_remove(widget);
350            }
351
352            // Make sure the component is shutdown properly
353            component.extract();
354        }
355
356        self.inner.rendered_state.clear();
357
358        self.inner.uid_counter = 1;
359    }
360
361    /// Returns an iterator over the components that returns mutable references.
362    ///
363    /// Each item will be [`Some`] if the async [`init_model()`] method
364    /// of the item returned and otherwise [`None`].
365    ///
366    /// [`init_model()`]: AsyncFactoryComponent::init_model
367    pub fn iter_mut(
368        &mut self,
369    ) -> impl DoubleEndedIterator<Item = Option<&mut C>> + ExactSizeIterator + FusedIterator {
370        self.inner
371            .components
372            .iter_mut()
373            .zip(self.inner.model_state.iter_mut())
374            .map(|(component, state)| {
375                state.changed = true;
376                component.get_mut()
377            })
378    }
379}
380
381impl<C: AsyncFactoryComponent> Deref for AsyncFactoryVecDequeGuard<'_, C>
382where
383    <C::ParentWidget as FactoryView>::ReturnedWidget: Clone,
384{
385    type Target = AsyncFactoryVecDeque<C>;
386
387    fn deref(&self) -> &Self::Target {
388        self.inner
389    }
390}
391
392#[derive(Debug)]
393/// A builder-pattern struct for building a [`AsyncFactoryVecDeque`].
394pub struct AsyncFactoryVecDequeBuilder<C>
395where
396    C: AsyncFactoryComponent,
397{
398    _component: PhantomData<C>,
399}
400
401impl<C> Default for AsyncFactoryVecDequeBuilder<C>
402where
403    C: AsyncFactoryComponent,
404{
405    fn default() -> Self {
406        Self::new()
407    }
408}
409
410impl<C> AsyncFactoryVecDequeBuilder<C>
411where
412    C: AsyncFactoryComponent,
413    C::ParentWidget: Default,
414{
415    /// Launch the factory with a default parent widget.
416    #[must_use]
417    pub fn launch_default(self) -> AsyncFactoryVecDequeConnector<C> {
418        self.launch(Default::default())
419    }
420}
421
422impl<C> AsyncFactoryVecDequeBuilder<C>
423where
424    C: AsyncFactoryComponent,
425{
426    /// Create a builder for this component.
427    #[must_use]
428    pub fn new() -> Self {
429        Self {
430            _component: PhantomData,
431        }
432    }
433
434    /// Launch the factory.
435    /// This is similar to [`Connector::launch`](crate::component::ComponentBuilder::launch).
436    pub fn launch(self, widget: C::ParentWidget) -> AsyncFactoryVecDequeConnector<C> {
437        let (output_sender, output_receiver) = crate::channel();
438
439        AsyncFactoryVecDequeConnector {
440            widget,
441            output_sender,
442            output_receiver,
443        }
444    }
445}
446
447#[derive(Debug)]
448/// Second stage of the builder-pattern for building a [`AsyncFactoryVecDeque`].
449pub struct AsyncFactoryVecDequeConnector<C>
450where
451    C: AsyncFactoryComponent,
452{
453    widget: C::ParentWidget,
454    output_sender: Sender<C::Output>,
455    output_receiver: Receiver<C::Output>,
456}
457
458impl<C> AsyncFactoryVecDequeConnector<C>
459where
460    C: AsyncFactoryComponent,
461    <C::ParentWidget as FactoryView>::ReturnedWidget: Clone,
462{
463    /// Forwards output events from child components to the designated sender.
464    pub fn forward<F, Msg>(self, sender_: &Sender<Msg>, f: F) -> AsyncFactoryVecDeque<C>
465    where
466        F: Fn(C::Output) -> Msg + Send + 'static,
467        C::Output: Send,
468        Msg: Send + 'static,
469    {
470        let Self {
471            widget,
472            output_sender,
473            output_receiver,
474        } = self;
475
476        let sender_clone = sender_.clone();
477        crate::spawn(async move {
478            while let Some(msg) = output_receiver.recv().await {
479                if sender_clone.send(f(msg)).is_err() {
480                    break;
481                }
482            }
483        });
484
485        AsyncFactoryVecDeque {
486            widget,
487            output_sender,
488            components: VecDeque::new(),
489            model_state: VecDeque::new(),
490            rendered_state: VecDeque::new(),
491            // 0 is always an invalid uid
492            uid_counter: 1,
493        }
494    }
495
496    /// Ignore output events from child components and just create the [`AsyncFactoryVecDeque`].
497    pub fn detach(self) -> AsyncFactoryVecDeque<C> {
498        let Self {
499            widget,
500            output_sender,
501            ..
502        } = self;
503        AsyncFactoryVecDeque {
504            widget,
505            output_sender,
506            components: VecDeque::new(),
507            model_state: VecDeque::new(),
508            rendered_state: VecDeque::new(),
509            // 0 is always an invalid uid
510            uid_counter: 1,
511        }
512    }
513}
514
515/// A container similar to [`VecDeque`] that can be used to store
516/// data associated with components that implement [`AsyncFactoryComponent`].
517///
518/// To access mutable methods of the factory, create a guard using [`Self::guard`].
519#[derive(Debug)]
520pub struct AsyncFactoryVecDeque<C: AsyncFactoryComponent>
521where
522    <C::ParentWidget as FactoryView>::ReturnedWidget: Clone,
523{
524    widget: C::ParentWidget,
525    output_sender: Sender<C::Output>,
526    components: VecDeque<AsyncComponentStorage<C>>,
527    model_state: VecDeque<ModelStateValue>,
528    rendered_state: VecDeque<RenderedState>,
529    uid_counter: usize,
530}
531
532impl<C: AsyncFactoryComponent> Drop for AsyncFactoryVecDeque<C>
533where
534    <C::ParentWidget as FactoryView>::ReturnedWidget: Clone,
535{
536    fn drop(&mut self) {
537        self.guard().clear();
538    }
539}
540
541impl<C: AsyncFactoryComponent> AsyncFactoryVecDeque<C>
542where
543    <C::ParentWidget as FactoryView>::ReturnedWidget: Clone,
544{
545    /// Creates a new [`AsyncFactoryVecDequeBuilder`].
546    #[must_use]
547    pub fn builder() -> AsyncFactoryVecDequeBuilder<C> {
548        AsyncFactoryVecDequeBuilder::new()
549    }
550
551    /// Provides a [`AsyncFactoryVecDequeGuard`] that can be used to edit the factory.
552    ///
553    /// The changes will be rendered on the widgets after the guard goes out of scope.
554    pub fn guard(&mut self) -> AsyncFactoryVecDequeGuard<'_, C> {
555        AsyncFactoryVecDequeGuard::new(self)
556    }
557
558    /// Updates the widgets according to the changes made to the factory.
559    /// All updates accumulate until this method is called and are handled
560    /// efficiently.
561    ///
562    /// For example, swapping two elements twice will only swap the data twice,
563    /// but won't cause any UI updates.
564    ///
565    /// Also, only modified elements will be updated.
566    fn render_changes(&mut self) {
567        let mut first_position_change_idx = None;
568
569        let components = &mut self.components;
570        let rendered_state = &mut self.rendered_state;
571        for (index, state) in self.model_state.iter().enumerate() {
572            if state.uid == rendered_state.front().map(|r| r.uid).unwrap_or_default() {
573                // Remove item from previously rendered list
574                rendered_state.pop_front();
575
576                if state.changed {
577                    // Update component
578                    components[index].state_change_notify();
579                }
580            } else if let Some(rendered_index) =
581                rendered_state.iter().position(|r| r.uid == state.uid)
582            {
583                if first_position_change_idx.is_none() {
584                    first_position_change_idx = Some(index);
585                }
586
587                // Remove item from previously rendered list
588                rendered_state.remove(rendered_index);
589
590                // Detach and re-attach item
591                let widget = components[index].returned_widget().unwrap();
592                if index == 0 {
593                    self.widget.factory_move_start(widget);
594                } else {
595                    let previous_widget = components[index - 1].returned_widget().unwrap();
596                    self.widget.factory_move_after(widget, previous_widget);
597                }
598
599                if state.changed {
600                    // Update component
601                    components[index].state_change_notify();
602                }
603            } else {
604                if first_position_change_idx.is_none() {
605                    first_position_change_idx = Some(index);
606                }
607
608                // The element doesn't exist yet
609                let insert_widget = components[index].widget();
610                let position = C::position(index);
611                let returned_widget = if index == 0 {
612                    self.widget.factory_prepend(insert_widget, &position)
613                } else {
614                    let previous_widget = components[index - 1].returned_widget().unwrap();
615                    self.widget
616                        .factory_insert_after(insert_widget, &position, previous_widget)
617                };
618                let component = components.remove(index).unwrap();
619                let dyn_index = &self.model_state[index].index;
620                let component = component.launch(dyn_index, returned_widget).unwrap();
621                components.insert(index, component);
622            }
623        }
624
625        // Reset change tracker
626        self.model_state.iter_mut().for_each(|s| s.changed = false);
627
628        // Set rendered state to the state of the model
629        // because everything should be up-to-date now.
630        self.rendered_state = self
631            .model_state
632            .iter()
633            .zip(components.iter())
634            .map(|(s, c)| {
635                let mut hasher = DefaultHasher::default();
636                c.returned_widget().unwrap().hash(&mut hasher);
637
638                RenderedState {
639                    uid: s.uid,
640                    #[cfg(feature = "libadwaita")]
641                    widget_hash: hasher.finish(),
642                }
643            })
644            .collect();
645
646        if let Some(change_index) = first_position_change_idx {
647            for (index, comp) in components.iter().enumerate().skip(change_index) {
648                let position = C::position(index);
649                self.widget
650                    .factory_update_position(comp.returned_widget().unwrap(), &position);
651            }
652        }
653    }
654
655    /// Returns the number of elements in the [`AsyncFactoryVecDeque`].
656    pub fn len(&self) -> usize {
657        self.components.len()
658    }
659
660    /// Returns true if the [`AsyncFactoryVecDeque`] is empty.
661    pub fn is_empty(&self) -> bool {
662        self.components.is_empty()
663    }
664
665    /// Send a message to one of the elements.
666    pub fn send(&self, index: usize, msg: C::Input) {
667        self.components[index].send(msg);
668    }
669
670    /// Send clone of a message to all of the elements.
671    pub fn broadcast(&self, msg: C::Input)
672    where
673        C::Input: Clone,
674    {
675        self.components.iter().for_each(|c| c.send(msg.clone()));
676    }
677
678    /// Tries to get an immutable reference to
679    /// the model of one element.
680    ///
681    /// Returns [`None`] if `index` is invalid or the async [`init_model()`] method
682    /// hasn't returned yet.
683    ///
684    /// [`init_model()`]: AsyncFactoryComponent::init_model
685    pub fn get(&self, index: usize) -> Option<&C> {
686        self.components
687            .get(index)
688            .and_then(AsyncComponentStorage::get)
689    }
690
691    /// Provides a reference to the model of the back element.
692    ///
693    /// Returns [`None`] if `index` is invalid or the async [`init_model()`] method
694    /// of the last element hasn't returned yet.
695    ///
696    /// [`init_model()`]: AsyncFactoryComponent::init_model
697    pub fn back(&self) -> Option<&C> {
698        self.get(self.len().wrapping_sub(1))
699    }
700
701    /// Provides a reference to the model of the front element.
702    ///
703    /// Returns [`None`] if `index` is invalid or the async [`init_model()`] method
704    /// of the first element hasn't returned yet.
705    ///
706    /// [`init_model()`]: AsyncFactoryComponent::init_model
707    pub fn front(&self) -> Option<&C> {
708        self.get(0)
709    }
710
711    /// Returns the widget all components are attached to.
712    pub const fn widget(&self) -> &C::ParentWidget {
713        &self.widget
714    }
715
716    /// Returns an iterator over the components.
717    ///
718    /// Each item will be [`Some`] if the async [`init_model()`] method
719    /// of the item returned and otherwise [`None`].
720    ///
721    /// [`init_model()`]: AsyncFactoryComponent::init_model
722    pub fn iter(
723        &self,
724    ) -> impl DoubleEndedIterator<Item = Option<&C>> + ExactSizeIterator + FusedIterator {
725        self.components.iter().map(AsyncComponentStorage::get)
726    }
727}