relm4/factory/sync/collections/
vec_deque.rs

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