Skip to main content

ferroui_dynamic_data/list/internal/
group.rs

1//! `Group<TObject, TGroup>` (`List/Internal/Group.cs`).
2
3use crate::list::{IExtendedList, IGroup, IObservableList, SourceList};
4use ferroui_system::IDisposable;
5use std::fmt;
6use std::hash::{Hash, Hasher};
7use std::rc::Rc;
8
9struct Inner<T, G> {
10    group_key: G,
11    source: SourceList<T>,
12}
13
14/// A group of the items of a list that share a group key (`Group<TObject, TGroup>`, the `IGroup`
15/// of the change sets of `GroupOn`): the grouping edits its list, and its observers watch it. A
16/// clone is the same group.
17///
18/// Deviation (DEVIATIONS.md, DynamicData): upstream's class is internal and its change sets hold
19/// the interface `IGroup`; here they hold this type, so it is public.
20pub struct Group<T, G> {
21    inner: Rc<Inner<T, G>>,
22}
23
24impl<T, G> Clone for Group<T, G> {
25    fn clone(&self) -> Self {
26        Self { inner: self.inner.clone() }
27    }
28}
29
30impl<T: Clone + PartialEq + 'static, G> Group<T, G> {
31    /// An empty group of `group_key` (`Group(TGroup)`).
32    pub(crate) fn new(group_key: G) -> Self {
33        Self { inner: Rc::new(Inner { group_key, source: SourceList::new() }) }
34    }
35
36    /// The group key (`GroupKey`).
37    pub fn group_key(&self) -> &G {
38        &self.inner.group_key
39    }
40
41    /// The items of the group (`List`).
42    pub fn list(&self) -> Rc<dyn IObservableList<T>> {
43        Rc::new(self.inner.source.clone())
44    }
45
46    /// The number of items.
47    pub(crate) fn count(&self) -> usize {
48        self.inner.source.count()
49    }
50
51    /// Edits the list of the group (`Edit`).
52    pub(crate) fn edit(&self, edit_action: impl FnOnce(&mut dyn IExtendedList<T>)) {
53        self.inner.source.edit(edit_action);
54    }
55
56    /// Whether `self` and `other` are the same group (`ReferenceEquals`).
57    pub fn ptr_eq(&self, other: &Self) -> bool {
58        Rc::ptr_eq(&self.inner, &other.inner)
59    }
60}
61
62impl<T: Clone + PartialEq + 'static, G> IGroup<T, G> for Group<T, G> {
63    fn group_key(&self) -> &G {
64        &self.inner.group_key
65    }
66
67    fn list(&self) -> Rc<dyn IObservableList<T>> {
68        Rc::new(self.inner.source.clone())
69    }
70}
71
72impl<T: Clone + PartialEq + 'static, G> IDisposable for Group<T, G> {
73    /// Ends the list of the group, which completes its observers (`Dispose`).
74    fn dispose(&self) {
75        self.inner.source.dispose();
76    }
77}
78
79impl<T, G: PartialEq> PartialEq for Group<T, G> {
80    /// Groups of the same key are equal (`Equals`).
81    fn eq(&self, other: &Self) -> bool {
82        Rc::ptr_eq(&self.inner, &other.inner) || self.inner.group_key == other.inner.group_key
83    }
84}
85
86impl<T, G: Eq> Eq for Group<T, G> {}
87
88impl<T, G: Hash> Hash for Group<T, G> {
89    /// The hash of the group key (`GetHashCode`).
90    fn hash<H: Hasher>(&self, state: &mut H) {
91        self.inner.group_key.hash(state);
92    }
93}
94
95impl<T: Clone + PartialEq + 'static, G: fmt::Display> fmt::Display for Group<T, G> {
96    /// `ToString`: `Group of {GroupKey} ({List.Count} records)`.
97    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
98        write!(f, "Group of {} ({} records)", self.inner.group_key, self.inner.source.count())
99    }
100}
101
102impl<T: Clone + PartialEq + 'static, G: fmt::Debug> fmt::Debug for Group<T, G> {
103    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
104        write!(f, "Group of {:?} ({} records)", self.inner.group_key, self.inner.source.count())
105    }
106}