Skip to main content

ferroui_dynamic_data/cache/
change_aware_cache.rs

1//! `ChangeAwareCache<TObject, TKey>` (`Cache/ChangeAwareCache.cs`).
2
3use super::{Change, ChangeReason, ChangeSet, ICache, IQuery};
4use ferroui_system::collections::generic::Dictionary;
5use std::hash::Hash;
6
7/// A keyed collection that records its changes until they are captured (`ChangeAwareCache<TObject,
8/// TKey>`): the building block of the cache operators.
9pub struct ChangeAwareCache<T, K> {
10    data: Dictionary<K, T>,
11    changes: Vec<Change<T, K>>,
12}
13
14impl<T: Clone, K: Eq + Hash + Clone> Default for ChangeAwareCache<T, K> {
15    fn default() -> Self {
16        Self::new()
17    }
18}
19
20impl<T: Clone, K: Eq + Hash + Clone> ChangeAwareCache<T, K> {
21    /// An empty cache.
22    pub fn new() -> Self {
23        Self { data: Dictionary::new(), changes: Vec::new() }
24    }
25
26    /// An empty cache with room for `capacity` items.
27    pub fn with_capacity(capacity: usize) -> Self {
28        Self { data: Dictionary::with_capacity(capacity), changes: Vec::with_capacity(capacity) }
29    }
30
31    /// A cache of the items of `data`, without changes (`ChangeAwareCache(Dictionary<TKey,
32    /// TObject>)`).
33    pub fn from_dictionary(data: Dictionary<K, T>) -> Self {
34        Self { data, changes: Vec::new() }
35    }
36
37    /// The underlying dictionary (`GetDictionary`).
38    pub fn dictionary(&self) -> &Dictionary<K, T> {
39        &self.data
40    }
41
42    /// The items, giving up the cache.
43    pub fn into_dictionary(self) -> Dictionary<K, T> {
44        self.data
45    }
46
47    /// Adds an item (`Add`).
48    ///
49    /// # Panics
50    /// When the key is there already (`ArgumentException` of the dictionary).
51    pub fn add(&mut self, item: T, key: K) {
52        self.changes.push(Change::new(ChangeReason::Add, key.clone(), item.clone()));
53        self.data.add(key, item);
54    }
55
56    /// The changes since the last capture, and a clean slate (`CaptureChanges`).
57    pub fn capture_changes(&mut self) -> ChangeSet<T, K> {
58        if self.changes.is_empty() {
59            return ChangeSet::empty();
60        }
61        ChangeSet::from(std::mem::take(&mut self.changes))
62    }
63
64    /// Whether there are changes not captured yet.
65    pub fn has_changes(&self) -> bool {
66        !self.changes.is_empty()
67    }
68}
69
70impl<T: Clone, K: Eq + Hash + Clone> IQuery<T, K> for ChangeAwareCache<T, K> {
71    fn count(&self) -> usize {
72        self.data.len()
73    }
74
75    fn items(&self) -> Vec<T> {
76        self.data.values().cloned().collect()
77    }
78
79    fn keys(&self) -> Vec<K> {
80        self.data.keys().cloned().collect()
81    }
82
83    fn key_values(&self) -> Vec<(K, T)> {
84        self.data.iter().map(|(key, item)| (key.clone(), item.clone())).collect()
85    }
86
87    fn lookup(&self, key: &K) -> Option<T> {
88        self.data.get(key).cloned()
89    }
90}
91
92impl<T: Clone, K: Eq + Hash + Clone> ICache<T, K> for ChangeAwareCache<T, K> {
93    fn add_or_update(&mut self, item: T, key: K) {
94        let change = match self.data.get(&key) {
95            Some(existing) => Change::update(key.clone(), item.clone(), existing.clone()),
96            None => Change::new(ChangeReason::Add, key.clone(), item.clone()),
97        };
98        self.changes.push(change);
99        self.data.insert(key, item);
100    }
101
102    fn clear(&mut self) {
103        let removed = self.data.iter().map(|(key, item)| Change::new(ChangeReason::Remove, key.clone(), item.clone()));
104        self.changes.extend(removed);
105        self.data.clear();
106    }
107
108    fn clone_changes(&mut self, changes: &ChangeSet<T, K>) {
109        for change in changes {
110            match change.reason() {
111                ChangeReason::Add | ChangeReason::Update => self.add_or_update(change.current().clone(), change.key().clone()),
112                ChangeReason::Remove => self.remove(change.key()),
113                ChangeReason::Refresh => self.refresh(change.key()),
114                ChangeReason::Moved => {}
115            }
116        }
117    }
118
119    fn refresh_all(&mut self) {
120        let refreshed = self.data.iter().map(|(key, item)| Change::new(ChangeReason::Refresh, key.clone(), item.clone()));
121        self.changes.extend(refreshed);
122    }
123
124    fn refresh_keys(&mut self, keys: &mut dyn Iterator<Item = K>) {
125        for key in keys {
126            self.refresh(&key);
127        }
128    }
129
130    fn refresh(&mut self, key: &K) {
131        if let Some(existing) = self.data.get(key) {
132            self.changes.push(Change::new(ChangeReason::Refresh, key.clone(), existing.clone()));
133        }
134    }
135
136    fn remove(&mut self, key: &K) {
137        if let Some(existing) = self.data.remove(key) {
138            self.changes.push(Change::new(ChangeReason::Remove, key.clone(), existing));
139        }
140    }
141
142    fn remove_keys(&mut self, keys: &mut dyn Iterator<Item = K>) {
143        for key in keys {
144            self.remove(&key);
145        }
146    }
147}