Skip to main content

ferroui_dynamic_data/cache/
intermediate_cache.rs

1//! `IntermediateCache<TObject, TKey>` and `IIntermediateCache<TObject, TKey>`
2//! (`Cache/IntermediateCache.cs`, `Cache/IIntermediateCache.cs`), with the edit conveniences of
3//! the latter (`ObservableCacheEx.AddOrUpdate`, `Clear` and `Remove` on `IIntermediateCache`).
4
5use super::{Change, ChangeSet, ICacheUpdater, IChangeSet, IConnectableCache, IObservableCache, ObservableCache};
6use ferroui_system::collections::generic::Dictionary;
7use ferroui_system::{IDisposable, IObservable};
8use std::hash::Hash;
9use std::rc::Rc;
10
11/// A cache whose edits give the keys of the items (`IIntermediateCache<TObject, TKey>`).
12pub trait IIntermediateCache<T, K>: IObservableCache<T, K> {
13    /// Runs an edit; its changes are delivered as one change set when it ends (`Edit`).
14    fn edit(&self, update: &mut dyn FnMut(&mut dyn ICacheUpdater<T, K>));
15}
16
17/// A cache without a key selector, whose edits give the keys (`IntermediateCache<TObject,
18/// TKey>`): the cache of the operators that keep items under keys of their own. A clone is a
19/// handle to the same cache.
20pub struct IntermediateCache<T, K> {
21    inner: ObservableCache<T, K>,
22}
23
24impl<T, K> Clone for IntermediateCache<T, K> {
25    fn clone(&self) -> Self {
26        Self { inner: self.inner.clone() }
27    }
28}
29
30impl<T: Clone + 'static, K: Eq + Hash + Clone + 'static> Default for IntermediateCache<T, K> {
31    fn default() -> Self {
32        Self::new()
33    }
34}
35
36impl<T: Clone + 'static, K: Eq + Hash + Clone + 'static> IntermediateCache<T, K> {
37    /// An empty cache (`IntermediateCache()`).
38    pub fn new() -> Self {
39        Self { inner: ObservableCache::without_key_selector() }
40    }
41
42    /// A cache that applies the change sets of `source` (`IntermediateCache(IObservable<IChangeSet>)`).
43    pub fn from_source<C: IChangeSet<T, K>>(source: Rc<dyn IObservable<C>>) -> Self {
44        Self { inner: ObservableCache::from_source(source) }
45    }
46
47    /// Runs an edit (`Edit(Action<ICacheUpdater>)`).
48    pub fn edit(&self, update: impl FnOnce(&mut dyn ICacheUpdater<T, K>)) {
49        self.inner.update_from_intermediate(update);
50    }
51
52    /// Holds back the notifications of count changes until the result is disposed (`SuspendCount`).
53    pub fn suspend_count(&self) -> Rc<dyn IDisposable> {
54        self.inner.suspend_count()
55    }
56
57    /// Holds back the notifications of changes until the result is disposed
58    /// (`SuspendNotifications`).
59    pub fn suspend_notifications(&self) -> Rc<dyn IDisposable> {
60        self.inner.suspend_notifications()
61    }
62
63    /// Adds `item` under `key`, or replaces the item of `key` (`AddOrUpdate(IIntermediateCache,
64    /// TObject, TKey)`).
65    pub fn add_or_update(&self, item: T, key: K) {
66        self.edit(|updater| updater.add_or_update_with_key(item, key));
67    }
68
69    /// Removes every item (`Clear(IIntermediateCache)`).
70    pub fn clear(&self) {
71        self.edit(|updater| updater.clear());
72    }
73
74    /// Removes the item of `key` (`Remove(IIntermediateCache, TKey)`).
75    pub fn remove_key(&self, key: K) {
76        self.edit(|updater| updater.remove_key(&key));
77    }
78
79    /// Removes the items of `keys` (`Remove(IIntermediateCache, IEnumerable<TKey>)`).
80    pub fn remove_keys(&self, keys: impl IntoIterator<Item = K>) {
81        let keys: Vec<K> = keys.into_iter().collect();
82        self.edit(|updater| updater.remove_keys(&mut keys.into_iter()));
83    }
84}
85
86impl<T: Clone + 'static, K: Eq + Hash + Clone + 'static> IConnectableCache<T, K> for IntermediateCache<T, K> {
87    fn count_changed(&self) -> Rc<dyn IObservable<usize>> {
88        self.inner.count_changed()
89    }
90
91    fn connect_with(&self, predicate: Option<Rc<dyn Fn(&T) -> bool>>, suppress_empty_change_sets: bool) -> Rc<dyn IObservable<ChangeSet<T, K>>> {
92        self.inner.connect_with(predicate, suppress_empty_change_sets)
93    }
94
95    fn preview_with(&self, predicate: Option<Rc<dyn Fn(&T) -> bool>>) -> Rc<dyn IObservable<ChangeSet<T, K>>> {
96        self.inner.preview_with(predicate)
97    }
98
99    fn watch(&self, key: K) -> Rc<dyn IObservable<Change<T, K>>> {
100        self.inner.watch(key)
101    }
102}
103
104impl<T: Clone + 'static, K: Eq + Hash + Clone + 'static> IObservableCache<T, K> for IntermediateCache<T, K> {
105    fn count(&self) -> usize {
106        self.inner.count()
107    }
108
109    fn items(&self) -> Vec<T> {
110        self.inner.items()
111    }
112
113    fn keys(&self) -> Vec<K> {
114        self.inner.keys()
115    }
116
117    fn key_values(&self) -> Dictionary<K, T> {
118        self.inner.key_values()
119    }
120
121    fn lookup(&self, key: &K) -> Option<T> {
122        self.inner.lookup(key)
123    }
124}
125
126impl<T: Clone + 'static, K: Eq + Hash + Clone + 'static> IIntermediateCache<T, K> for IntermediateCache<T, K> {
127    fn edit(&self, update: &mut dyn FnMut(&mut dyn ICacheUpdater<T, K>)) {
128        self.inner.update_from_intermediate(|updater| update(updater));
129    }
130}
131
132impl<T: Clone + 'static, K: Eq + Hash + Clone + 'static> IDisposable for IntermediateCache<T, K> {
133    fn dispose(&self) {
134        self.inner.dispose();
135    }
136}