Skip to main content

ferroui_dynamic_data/cache/
source_cache.rs

1//! `SourceCache<TObject, TKey>` and `ISourceCache<TObject, TKey>` (`Cache/SourceCache.cs`,
2//! `Cache/ISourceCache.cs`).
3
4use super::internal::KeySelector;
5use super::{Change, ChangeSet, IConnectableCache, IObservableCache, ISourceUpdater, 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 items are edited by its owner (`ISourceCache<TObject, TKey>`).
12pub trait ISourceCache<T, K>: IObservableCache<T, K> {
13    /// The key selector of the items (`KeySelector`).
14    fn key_selector(&self) -> KeySelector<T, K>;
15    /// Runs an edit; its changes are delivered as one change set when it ends (`Edit`).
16    fn edit(&self, update: &mut dyn FnMut(&mut dyn ISourceUpdater<T, K>));
17}
18
19/// The source of a reactive keyed collection (`SourceCache<TObject, TKey>`): edits make change
20/// sets, which `connect` delivers to the operators.
21pub struct SourceCache<T, K> {
22    inner: ObservableCache<T, K>,
23    key_selector: KeySelector<T, K>,
24}
25
26impl<T, K> Clone for SourceCache<T, K> {
27    fn clone(&self) -> Self {
28        Self { inner: self.inner.clone(), key_selector: self.key_selector.clone() }
29    }
30}
31
32impl<T: Clone + 'static, K: Eq + Hash + Clone + 'static> SourceCache<T, K> {
33    /// An empty cache whose items are keyed by `key_selector`.
34    pub fn new(key_selector: impl Fn(&T) -> K + 'static) -> Self {
35        let key_selector: KeySelector<T, K> = Rc::new(key_selector);
36        let selector = key_selector.clone();
37        Self { inner: ObservableCache::new(move |item| selector(item)), key_selector }
38    }
39
40    /// Runs an edit (`Edit(Action<ISourceUpdater>)`).
41    pub fn edit(&self, update: impl FnOnce(&mut dyn ISourceUpdater<T, K>)) {
42        self.inner.update_from_source(update);
43    }
44
45    /// Holds back the notifications of count changes (`SuspendCount`).
46    pub fn suspend_count(&self) -> Rc<dyn IDisposable> {
47        self.inner.suspend_count()
48    }
49
50    /// Holds back the notifications of changes (`SuspendNotifications`).
51    pub fn suspend_notifications(&self) -> Rc<dyn IDisposable> {
52        self.inner.suspend_notifications()
53    }
54
55    /// The observable cache this source edits.
56    pub fn as_observable_cache_inner(&self) -> &ObservableCache<T, K> {
57        &self.inner
58    }
59}
60
61impl<T: Clone + 'static, K: Eq + Hash + Clone + 'static> IConnectableCache<T, K> for SourceCache<T, K> {
62    fn count_changed(&self) -> Rc<dyn IObservable<usize>> {
63        self.inner.count_changed()
64    }
65
66    fn connect_with(&self, predicate: Option<Rc<dyn Fn(&T) -> bool>>, suppress_empty_change_sets: bool) -> Rc<dyn IObservable<ChangeSet<T, K>>> {
67        self.inner.connect_with(predicate, suppress_empty_change_sets)
68    }
69
70    fn preview_with(&self, predicate: Option<Rc<dyn Fn(&T) -> bool>>) -> Rc<dyn IObservable<ChangeSet<T, K>>> {
71        self.inner.preview_with(predicate)
72    }
73
74    fn watch(&self, key: K) -> Rc<dyn IObservable<Change<T, K>>> {
75        self.inner.watch(key)
76    }
77}
78
79impl<T: Clone + 'static, K: Eq + Hash + Clone + 'static> IObservableCache<T, K> for SourceCache<T, K> {
80    fn count(&self) -> usize {
81        self.inner.count()
82    }
83
84    fn items(&self) -> Vec<T> {
85        self.inner.items()
86    }
87
88    fn keys(&self) -> Vec<K> {
89        self.inner.keys()
90    }
91
92    fn key_values(&self) -> Dictionary<K, T> {
93        self.inner.key_values()
94    }
95
96    fn lookup(&self, key: &K) -> Option<T> {
97        self.inner.lookup(key)
98    }
99}
100
101impl<T: Clone + 'static, K: Eq + Hash + Clone + 'static> ISourceCache<T, K> for SourceCache<T, K> {
102    fn key_selector(&self) -> KeySelector<T, K> {
103        self.key_selector.clone()
104    }
105
106    fn edit(&self, update: &mut dyn FnMut(&mut dyn ISourceUpdater<T, K>)) {
107        self.inner.update_from_source(|updater| update(updater));
108    }
109}
110
111impl<T: Clone + 'static, K: Eq + Hash + Clone + 'static> IDisposable for SourceCache<T, K> {
112    fn dispose(&self) {
113        self.inner.dispose();
114    }
115}