ferroui_dynamic_data/binding/
observable_collection_adaptor.rs1use super::{BindingOptions, IObservableCollection, IObservableCollectionAdaptor};
9use crate::cache::internal::Cache;
10use crate::cache::{ChangeReason, ChangeSet, ICache, IQuery};
11use crate::list::IChangeSetAdaptor;
12use crate::DynamicDataOptions;
13use std::cell::{Cell, RefCell};
14use std::hash::Hash;
15use std::rc::Rc;
16
17pub struct ListObservableCollectionAdaptor<T: Clone + PartialEq + 'static> {
20 collection: Rc<dyn IObservableCollection<T>>,
21 refresh_threshold: usize,
22 #[allow(dead_code)]
24 allow_replace: bool,
25 reset_on_first_time_load: bool,
26 loaded: Cell<bool>,
27}
28
29impl<T: Clone + PartialEq + 'static> ListObservableCollectionAdaptor<T> {
30 pub fn new(collection: Rc<dyn IObservableCollection<T>>) -> Self {
33 Self::with_options(collection, DynamicDataOptions::binding())
34 }
35
36 pub fn with_options(collection: Rc<dyn IObservableCollection<T>>, options: BindingOptions) -> Self {
39 Self::with_threshold(collection, options.reset_threshold, options.use_replace_for_updates, options.reset_on_first_time_load)
40 }
41
42 pub fn with_threshold(collection: Rc<dyn IObservableCollection<T>>, refresh_threshold: usize, allow_replace: bool, reset_on_first_time_load: bool) -> Self {
45 Self { collection, refresh_threshold, allow_replace, reset_on_first_time_load, loaded: Cell::new(false) }
46 }
47}
48
49impl<T: Clone + PartialEq + 'static> IChangeSetAdaptor<T> for ListObservableCollectionAdaptor<T> {
50 fn adapt(&self, changes: &crate::list::ChangeSet<T>) {
51 if changes.total_changes() - changes.refreshes() > self.refresh_threshold || (!self.loaded.get() && self.reset_on_first_time_load) {
52 let suspension = self.collection.suspend_notifications();
53 self.collection.clone_changes(changes);
54 self.loaded.set(true);
55 suspension.dispose();
56 } else {
57 self.collection.clone_changes(changes);
58 }
59 }
60}
61
62pub struct ObservableCollectionAdaptor<T, K> {
65 cache: RefCell<Cache<T, K>>,
66 refresh_threshold: usize,
67 use_replace_for_updates: bool,
68 reset_on_first_time_load: bool,
69 loaded: Cell<bool>,
70}
71
72impl<T: Clone + PartialEq + 'static, K: Eq + Hash + Clone + 'static> Default for ObservableCollectionAdaptor<T, K> {
73 fn default() -> Self {
76 Self::new(BindingOptions::DEFAULT_RESET_THRESHOLD, BindingOptions::DEFAULT_USE_REPLACE_FOR_UPDATES, BindingOptions::DEFAULT_RESET_ON_FIRST_TIME_LOAD)
77 }
78}
79
80impl<T: Clone + PartialEq + 'static, K: Eq + Hash + Clone + 'static> ObservableCollectionAdaptor<T, K> {
81 pub fn new(refresh_threshold: usize, use_replace_for_updates: bool, reset_on_first_time_load: bool) -> Self {
83 Self { cache: RefCell::new(Cache::new()), refresh_threshold, use_replace_for_updates, reset_on_first_time_load, loaded: Cell::new(false) }
84 }
85
86 pub fn with_options(options: BindingOptions) -> Self {
88 Self::new(options.reset_threshold, options.use_replace_for_updates, options.reset_on_first_time_load)
89 }
90
91 pub fn with_use_replace_for_updates(use_replace_for_updates: bool) -> Self {
93 Self::new(BindingOptions::DEFAULT_RESET_THRESHOLD, use_replace_for_updates, BindingOptions::DEFAULT_RESET_ON_FIRST_TIME_LOAD)
94 }
95
96 fn do_update(&self, changes: &ChangeSet<T, K>, list: &dyn IObservableCollection<T>) {
97 for change in changes {
98 match change.reason() {
99 ChangeReason::Add => list.add(change.current().clone()),
100 ChangeReason::Remove => {
101 list.remove(change.current());
102 }
103 ChangeReason::Update => {
104 let previous = change.previous().expect("an update has a previous item");
105 if self.use_replace_for_updates {
108 let index = list.index_of(previous).expect("Cannot find index of original item. Either it does not exist in the list or the hashcode has mutated");
109 list.set(index, change.current().clone());
110 } else {
111 list.remove(previous);
112 list.add(change.current().clone());
113 }
114 }
115 ChangeReason::Refresh | ChangeReason::Moved => {}
116 }
117 }
118 }
119}
120
121impl<T: Clone + PartialEq + 'static, K: Eq + Hash + Clone + 'static> IObservableCollectionAdaptor<T, K> for ObservableCollectionAdaptor<T, K> {
122 fn adapt(&self, changes: &ChangeSet<T, K>, collection: &dyn IObservableCollection<T>) {
123 self.cache.borrow_mut().clone_changes(changes);
124
125 if changes.count() - changes.refreshes() > self.refresh_threshold || (!self.loaded.get() && self.reset_on_first_time_load) {
126 self.loaded.set(true);
127 let items = self.cache.borrow().items();
128 let suspension = collection.suspend_notifications();
129 collection.load(items);
130 suspension.dispose();
131 } else {
132 let suspension = collection.suspend_count();
133 self.do_update(changes, collection);
134 suspension.dispose();
135 }
136 }
137}