Skip to main content

ferroui_dynamic_data/list/
change_set.rs

1//! `ChangeSet<T>` and `IChangeSet<T>` (`List/ChangeSet.cs`, `List/IChangeSet.cs`).
2
3use super::{Change, ListChangeReason};
4use std::fmt;
5use std::ops::Deref;
6use std::rc::Rc;
7
8/// The changes of one edit of a list (`ChangeSet<T>`): shared and immutable, as the change sets of
9/// caches are.
10pub struct ChangeSet<T> {
11    changes: Rc<Vec<Change<T>>>,
12}
13
14impl<T> Clone for ChangeSet<T> {
15    fn clone(&self) -> Self {
16        Self { changes: self.changes.clone() }
17    }
18}
19
20impl<T> Default for ChangeSet<T> {
21    fn default() -> Self {
22        Self::empty()
23    }
24}
25
26impl<T> ChangeSet<T> {
27    /// A change set without changes (`ChangeSet<T>.Empty`).
28    pub fn empty() -> Self {
29        Self { changes: Rc::new(Vec::new()) }
30    }
31
32    /// The changes, in order.
33    pub fn changes(&self) -> &[Change<T>] {
34        &self.changes
35    }
36
37    /// The number of changes (`Count`).
38    pub fn count(&self) -> usize {
39        self.changes.len()
40    }
41
42    /// The number of items added, ranges counted by their items (`Adds`).
43    pub fn adds(&self) -> usize {
44        self.changes
45            .iter()
46            .map(|change| match change.reason() {
47                ListChangeReason::Add => 1,
48                ListChangeReason::AddRange => change.range().count(),
49                _ => 0,
50            })
51            .sum()
52    }
53
54    /// The number of moves (`Moves`).
55    pub fn moves(&self) -> usize {
56        self.changes.iter().filter(|change| change.reason() == ListChangeReason::Moved).count()
57    }
58
59    /// The number of refreshes (`Refreshes`).
60    pub fn refreshes(&self) -> usize {
61        self.changes.iter().filter(|change| change.reason() == ListChangeReason::Refresh).count()
62    }
63
64    /// The number of items removed, ranges and clears counted by their items (`Removes`).
65    pub fn removes(&self) -> usize {
66        self.changes
67            .iter()
68            .map(|change| match change.reason() {
69                ListChangeReason::Remove => 1,
70                ListChangeReason::RemoveRange | ListChangeReason::Clear => change.range().count(),
71                _ => 0,
72            })
73            .sum()
74    }
75
76    /// The number of replacements (`Replaced`).
77    pub fn replaced(&self) -> usize {
78        self.changes.iter().filter(|change| change.reason() == ListChangeReason::Replace).count()
79    }
80
81    /// The number of changed items (`TotalChanges`).
82    pub fn total_changes(&self) -> usize {
83        self.adds() + self.removes() + self.refreshes() + self.replaced() + self.moves()
84    }
85
86    /// Whether `self` and `other` are the same change set (`ReferenceEquals`).
87    pub fn ptr_eq(&self, other: &Self) -> bool {
88        Rc::ptr_eq(&self.changes, &other.changes)
89    }
90}
91
92impl<T> From<Vec<Change<T>>> for ChangeSet<T> {
93    fn from(changes: Vec<Change<T>>) -> Self {
94        Self { changes: Rc::new(changes) }
95    }
96}
97
98impl<T> FromIterator<Change<T>> for ChangeSet<T> {
99    fn from_iter<I: IntoIterator<Item = Change<T>>>(iter: I) -> Self {
100        Self::from(iter.into_iter().collect::<Vec<_>>())
101    }
102}
103
104impl<T> Deref for ChangeSet<T> {
105    type Target = [Change<T>];
106
107    fn deref(&self) -> &Self::Target {
108        &self.changes
109    }
110}
111
112impl<'a, T> IntoIterator for &'a ChangeSet<T> {
113    type Item = &'a Change<T>;
114    type IntoIter = std::slice::Iter<'a, Change<T>>;
115
116    fn into_iter(self) -> Self::IntoIter {
117        self.changes.iter()
118    }
119}
120
121impl<T: PartialEq> PartialEq for ChangeSet<T> {
122    fn eq(&self, other: &Self) -> bool {
123        self.changes == other.changes
124    }
125}
126
127impl<T: fmt::Debug> fmt::Debug for ChangeSet<T> {
128    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
129        f.debug_list().entries(self.changes.iter()).finish()
130    }
131}
132
133/// A change set of a list, of any form (`IChangeSet<T>`): the plain one, and the paged and
134/// virtual ones, which hold a plain one with more parts.
135pub trait IChangeSet<T>: Clone + 'static {
136    /// The changes.
137    fn change_set(&self) -> &ChangeSet<T>;
138}
139
140impl<T: 'static> IChangeSet<T> for ChangeSet<T> {
141    fn change_set(&self) -> &ChangeSet<T> {
142        self
143    }
144}