Skip to main content

ferroui_dynamic_data/cache/ops/
merge_change_sets.rs

1//! `MergeChangeSets` (`Cache/ObservableCacheEx.MergeChangeSets.cs`): the change sets of several
2//! caches merged into those of one.
3//!
4//! Deviation (DEVIATIONS.md, DynamicData): the upstream overloads take three kinds of sources,
5//! each a trait of its own here, and the overloads with an `IComparer` are the `_ordered_by`
6//! methods:
7//! - a sequence of change sets with another one or others: provided methods of
8//!   [`ObservableCacheEx`](crate::cache::ObservableCacheEx) (`merge_change_sets(other)`,
9//!   `merge_change_sets_many(others)`);
10//! - an enumerable of sequences: [`CacheChangeSetSourcesEx`], for a slice or a `Vec`;
11//! - a sequence of sequences: [`ObservableCacheChangeSetsEx`].
12//!
13//! Without a comparer, the first value of a key stays until it is removed; with one
14//! (`_ordered_by`), the value of a key is the least among the caches. The default equality of the
15//! items (`EqualityComparer<TObject>.Default`) is `PartialEq`; `_with_comparer` takes another.
16
17use crate::cache::internal::{default_equality_comparer, merge_change_sets, sources_observable};
18use crate::cache::ChangeSet;
19use ferroui_reactive::concurrency::IScheduler;
20use ferroui_system::IObservable;
21use std::cmp::Ordering;
22use std::hash::Hash;
23use std::rc::Rc;
24
25macro_rules! merge_change_sets_methods {
26    () => {
27        /// The change sets of the sequence and of `other`, merged; it completes when both have
28        /// completed (`MergeChangeSets(IObservable<IChangeSet>, IObservable<IChangeSet>,
29        /// IScheduler? = null, bool completable = true)`).
30        fn merge_change_sets(
31            &self,
32            other: std::rc::Rc<dyn ferroui_system::IObservable<crate::cache::ChangeSet<T, K>>>,
33        ) -> std::rc::Rc<dyn ferroui_system::IObservable<crate::cache::ChangeSet<T, K>>>
34        where
35            T: PartialEq,
36        {
37            crate::cache::ops::merge_change_sets::merge_sources(vec![self.change_sets(), other], None, None, None, true)
38        }
39
40        /// [`merge_change_sets`](Self::merge_change_sets) with the equality of the items
41        /// (`MergeChangeSets(.., IObservable<IChangeSet>, IEqualityComparer<TObject>, ..)`).
42        fn merge_change_sets_with_comparer(
43            &self,
44            other: std::rc::Rc<dyn ferroui_system::IObservable<crate::cache::ChangeSet<T, K>>>,
45            equality_comparer: impl Fn(&T, &T) -> bool + 'static,
46        ) -> std::rc::Rc<dyn ferroui_system::IObservable<crate::cache::ChangeSet<T, K>>> {
47            crate::cache::ops::merge_change_sets::merge_sources_with(vec![self.change_sets(), other], std::rc::Rc::new(equality_comparer), None, None, true)
48        }
49
50        /// [`merge_change_sets`](Self::merge_change_sets) where the value of a key is the least by
51        /// `comparer` (`MergeChangeSets(.., IObservable<IChangeSet>, IComparer<TObject>, ..)`).
52        fn merge_change_sets_ordered_by(
53            &self,
54            other: std::rc::Rc<dyn ferroui_system::IObservable<crate::cache::ChangeSet<T, K>>>,
55            comparer: std::rc::Rc<dyn Fn(&T, &T) -> std::cmp::Ordering>,
56        ) -> std::rc::Rc<dyn ferroui_system::IObservable<crate::cache::ChangeSet<T, K>>>
57        where
58            T: PartialEq,
59        {
60            crate::cache::ops::merge_change_sets::merge_sources(vec![self.change_sets(), other], None, Some(comparer), None, true)
61        }
62
63        /// [`merge_change_sets`](Self::merge_change_sets) with every argument: the equality of the
64        /// items (`PartialEq` when `None`), the comparer, the scheduler that enumerates the two
65        /// sequences, and whether the merge completes after them
66        /// (`MergeChangeSets(.., IObservable<IChangeSet>, IEqualityComparer<TObject>,
67        /// IComparer<TObject>, IScheduler?, bool)`).
68        fn merge_change_sets_with(
69            &self,
70            other: std::rc::Rc<dyn ferroui_system::IObservable<crate::cache::ChangeSet<T, K>>>,
71            equality_comparer: Option<std::rc::Rc<dyn Fn(&T, &T) -> bool>>,
72            comparer: Option<std::rc::Rc<dyn Fn(&T, &T) -> std::cmp::Ordering>>,
73            scheduler: Option<std::rc::Rc<dyn ferroui_reactive::concurrency::IScheduler>>,
74            completable: bool,
75        ) -> std::rc::Rc<dyn ferroui_system::IObservable<crate::cache::ChangeSet<T, K>>>
76        where
77            T: PartialEq,
78        {
79            crate::cache::ops::merge_change_sets::merge_sources(vec![self.change_sets(), other], equality_comparer, comparer, scheduler, completable)
80        }
81
82        /// The change sets of the sequence and of `others`, merged
83        /// (`MergeChangeSets(IObservable<IChangeSet>, IEnumerable<IObservable<IChangeSet>>,
84        /// IScheduler? = null, bool completable = true)`).
85        fn merge_change_sets_many(
86            &self,
87            others: Vec<std::rc::Rc<dyn ferroui_system::IObservable<crate::cache::ChangeSet<T, K>>>>,
88        ) -> std::rc::Rc<dyn ferroui_system::IObservable<crate::cache::ChangeSet<T, K>>>
89        where
90            T: PartialEq,
91        {
92            let mut sources = vec![self.change_sets()];
93            sources.extend(others);
94            crate::cache::ops::merge_change_sets::merge_sources(sources, None, None, None, true)
95        }
96
97        /// [`merge_change_sets_many`](Self::merge_change_sets_many) with every argument
98        /// (`MergeChangeSets(.., IEnumerable<IObservable<IChangeSet>>, IEqualityComparer<TObject>,
99        /// IComparer<TObject>, IScheduler?, bool)`).
100        fn merge_change_sets_many_with(
101            &self,
102            others: Vec<std::rc::Rc<dyn ferroui_system::IObservable<crate::cache::ChangeSet<T, K>>>>,
103            equality_comparer: Option<std::rc::Rc<dyn Fn(&T, &T) -> bool>>,
104            comparer: Option<std::rc::Rc<dyn Fn(&T, &T) -> std::cmp::Ordering>>,
105            scheduler: Option<std::rc::Rc<dyn ferroui_reactive::concurrency::IScheduler>>,
106            completable: bool,
107        ) -> std::rc::Rc<dyn ferroui_system::IObservable<crate::cache::ChangeSet<T, K>>>
108        where
109            T: PartialEq,
110        {
111            let mut sources = vec![self.change_sets()];
112            sources.extend(others);
113            crate::cache::ops::merge_change_sets::merge_sources(sources, equality_comparer, comparer, scheduler, completable)
114        }
115    };
116}
117pub(crate) use merge_change_sets_methods;
118
119/// The merge of an enumerable of sequences, with the default equality when none is given.
120pub(crate) fn merge_sources<T: Clone + PartialEq + 'static, K: Eq + Hash + Clone + 'static>(
121    sources: Vec<Rc<dyn IObservable<ChangeSet<T, K>>>>,
122    equality_comparer: Option<Rc<dyn Fn(&T, &T) -> bool>>,
123    comparer: Option<Rc<dyn Fn(&T, &T) -> Ordering>>,
124    scheduler: Option<Rc<dyn IScheduler>>,
125    completable: bool,
126) -> Rc<dyn IObservable<ChangeSet<T, K>>> {
127    merge_sources_with(sources, equality_comparer.unwrap_or_else(default_equality_comparer), comparer, scheduler, completable)
128}
129
130/// The merge of an enumerable of sequences (`new MergeChangeSets(IEnumerable<..>, ..)`).
131pub(crate) fn merge_sources_with<T: Clone + 'static, K: Eq + Hash + Clone + 'static>(
132    sources: Vec<Rc<dyn IObservable<ChangeSet<T, K>>>>,
133    equality_comparer: Rc<dyn Fn(&T, &T) -> bool>,
134    comparer: Option<Rc<dyn Fn(&T, &T) -> Ordering>>,
135    scheduler: Option<Rc<dyn IScheduler>>,
136    completable: bool,
137) -> Rc<dyn IObservable<ChangeSet<T, K>>> {
138    merge_change_sets(sources_observable(sources, completable, scheduler), equality_comparer, comparer)
139}
140
141/// `MergeChangeSets` of an enumerable of sequences of change sets of caches
142/// (`MergeChangeSets(this IEnumerable<IObservable<IChangeSet<TObject, TKey>>>, ..)`): the
143/// sequences are enumerated when the merge is subscribed, and the merge completes after them
144/// unless `completable` is false.
145pub trait CacheChangeSetSourcesEx<T, K> {
146    /// The change sets of the sequences, merged
147    /// (`MergeChangeSets(IScheduler? = null, bool completable = true)`).
148    fn merge_change_sets(&self) -> Rc<dyn IObservable<ChangeSet<T, K>>>
149    where
150        T: PartialEq;
151
152    /// With the equality of the items (`MergeChangeSets(IEqualityComparer<TObject>, ..)`).
153    fn merge_change_sets_with_comparer(&self, equality_comparer: impl Fn(&T, &T) -> bool + 'static) -> Rc<dyn IObservable<ChangeSet<T, K>>>;
154
155    /// Where the value of a key is the least by `comparer` (`MergeChangeSets(IComparer<TObject>,
156    /// ..)`).
157    fn merge_change_sets_ordered_by(&self, comparer: Rc<dyn Fn(&T, &T) -> Ordering>) -> Rc<dyn IObservable<ChangeSet<T, K>>>
158    where
159        T: PartialEq;
160
161    /// With every argument: the equality of the items (`PartialEq` when `None`), the comparer, the
162    /// scheduler that enumerates the sequences, and whether the merge completes after them
163    /// (`MergeChangeSets(IEqualityComparer<TObject>, IComparer<TObject>, IScheduler?, bool)`).
164    fn merge_change_sets_with(
165        &self,
166        equality_comparer: Option<Rc<dyn Fn(&T, &T) -> bool>>,
167        comparer: Option<Rc<dyn Fn(&T, &T) -> Ordering>>,
168        scheduler: Option<Rc<dyn IScheduler>>,
169        completable: bool,
170    ) -> Rc<dyn IObservable<ChangeSet<T, K>>>
171    where
172        T: PartialEq;
173}
174
175impl<T: Clone + 'static, K: Eq + Hash + Clone + 'static> CacheChangeSetSourcesEx<T, K> for [Rc<dyn IObservable<ChangeSet<T, K>>>] {
176    fn merge_change_sets(&self) -> Rc<dyn IObservable<ChangeSet<T, K>>>
177    where
178        T: PartialEq,
179    {
180        merge_sources(self.to_vec(), None, None, None, true)
181    }
182
183    fn merge_change_sets_with_comparer(&self, equality_comparer: impl Fn(&T, &T) -> bool + 'static) -> Rc<dyn IObservable<ChangeSet<T, K>>> {
184        merge_sources_with(self.to_vec(), Rc::new(equality_comparer), None, None, true)
185    }
186
187    fn merge_change_sets_ordered_by(&self, comparer: Rc<dyn Fn(&T, &T) -> Ordering>) -> Rc<dyn IObservable<ChangeSet<T, K>>>
188    where
189        T: PartialEq,
190    {
191        merge_sources(self.to_vec(), None, Some(comparer), None, true)
192    }
193
194    fn merge_change_sets_with(
195        &self,
196        equality_comparer: Option<Rc<dyn Fn(&T, &T) -> bool>>,
197        comparer: Option<Rc<dyn Fn(&T, &T) -> Ordering>>,
198        scheduler: Option<Rc<dyn IScheduler>>,
199        completable: bool,
200    ) -> Rc<dyn IObservable<ChangeSet<T, K>>>
201    where
202        T: PartialEq,
203    {
204        merge_sources(self.to_vec(), equality_comparer, comparer, scheduler, completable)
205    }
206}
207
208/// `MergeChangeSets` of a sequence of sequences of change sets of caches
209/// (`MergeChangeSets(this IObservable<IObservable<IChangeSet<TObject, TKey>>>, ..)`): each
210/// sequence is merged as it arrives; the merge completes when the outer sequence and every inner
211/// one have completed.
212pub trait ObservableCacheChangeSetsEx<T, K> {
213    /// The change sets of the sequences, merged (`MergeChangeSets()`).
214    fn merge_change_sets(&self) -> Rc<dyn IObservable<ChangeSet<T, K>>>
215    where
216        T: PartialEq;
217
218    /// With the equality of the items (`MergeChangeSets(IEqualityComparer<TObject>)`).
219    fn merge_change_sets_with_comparer(&self, equality_comparer: impl Fn(&T, &T) -> bool + 'static) -> Rc<dyn IObservable<ChangeSet<T, K>>>;
220
221    /// Where the value of a key is the least by `comparer` (`MergeChangeSets(IComparer<TObject>)`).
222    fn merge_change_sets_ordered_by(&self, comparer: Rc<dyn Fn(&T, &T) -> Ordering>) -> Rc<dyn IObservable<ChangeSet<T, K>>>
223    where
224        T: PartialEq;
225
226    /// With the equality of the items (`PartialEq` when `None`) and the comparer
227    /// (`MergeChangeSets(IEqualityComparer<TObject>, IComparer<TObject>)`).
228    fn merge_change_sets_with(&self, equality_comparer: Option<Rc<dyn Fn(&T, &T) -> bool>>, comparer: Option<Rc<dyn Fn(&T, &T) -> Ordering>>) -> Rc<dyn IObservable<ChangeSet<T, K>>>
229    where
230        T: PartialEq;
231}
232
233impl<T: Clone + 'static, K: Eq + Hash + Clone + 'static> ObservableCacheChangeSetsEx<T, K> for Rc<dyn IObservable<Rc<dyn IObservable<ChangeSet<T, K>>>>> {
234    fn merge_change_sets(&self) -> Rc<dyn IObservable<ChangeSet<T, K>>>
235    where
236        T: PartialEq,
237    {
238        merge_change_sets(self.clone(), default_equality_comparer(), None)
239    }
240
241    fn merge_change_sets_with_comparer(&self, equality_comparer: impl Fn(&T, &T) -> bool + 'static) -> Rc<dyn IObservable<ChangeSet<T, K>>> {
242        merge_change_sets(self.clone(), Rc::new(equality_comparer), None)
243    }
244
245    fn merge_change_sets_ordered_by(&self, comparer: Rc<dyn Fn(&T, &T) -> Ordering>) -> Rc<dyn IObservable<ChangeSet<T, K>>>
246    where
247        T: PartialEq,
248    {
249        merge_change_sets(self.clone(), default_equality_comparer(), Some(comparer))
250    }
251
252    fn merge_change_sets_with(&self, equality_comparer: Option<Rc<dyn Fn(&T, &T) -> bool>>, comparer: Option<Rc<dyn Fn(&T, &T) -> Ordering>>) -> Rc<dyn IObservable<ChangeSet<T, K>>>
253    where
254        T: PartialEq,
255    {
256        merge_change_sets(self.clone(), equality_comparer.unwrap_or_else(default_equality_comparer), comparer)
257    }
258}