ferroui_dynamic_data/list/ops/
combine.rs1use crate::cache::internal::CombineOperator;
22use crate::list::internal::{combiner, dynamic_combiner};
23use crate::list::{ChangeSet, IObservableList, ISourceList, ObservableList, SourceList};
24use ferroui_system::IObservable;
25use std::hash::Hash;
26use std::rc::Rc;
27
28pub(crate) fn combine_with_others<T: Clone + Eq + Hash + 'static>(
31 source: Rc<dyn IObservable<ChangeSet<T>>>,
32 kind: CombineOperator,
33 others: Vec<Rc<dyn IObservable<ChangeSet<T>>>>,
34) -> Rc<dyn IObservable<ChangeSet<T>>> {
35 let mut items: Vec<Rc<dyn IObservable<ChangeSet<T>>>> = Vec::with_capacity(others.len() + 1);
37 for candidate in std::iter::once(source).chain(others) {
38 if !items.iter().any(|item| std::ptr::addr_eq(Rc::as_ptr(item), Rc::as_ptr(&candidate))) {
39 items.push(candidate);
40 }
41 }
42 combiner(items, kind)
43}
44
45pub trait ListChangeSetSource: 'static {
48 type Item: Clone + PartialEq + 'static;
50
51 fn source_change_sets(&self) -> Rc<dyn IObservable<ChangeSet<Self::Item>>>;
53}
54
55impl<T: Clone + PartialEq + 'static> ListChangeSetSource for Rc<dyn IObservable<ChangeSet<T>>> {
56 type Item = T;
57
58 fn source_change_sets(&self) -> Rc<dyn IObservable<ChangeSet<T>>> {
59 self.clone()
60 }
61}
62
63impl<T: Clone + PartialEq + 'static> ListChangeSetSource for SourceList<T> {
64 type Item = T;
65
66 fn source_change_sets(&self) -> Rc<dyn IObservable<ChangeSet<T>>> {
67 self.connect()
68 }
69}
70
71impl<T: Clone + PartialEq + 'static> ListChangeSetSource for ObservableList<T> {
72 type Item = T;
73
74 fn source_change_sets(&self) -> Rc<dyn IObservable<ChangeSet<T>>> {
75 self.connect()
76 }
77}
78
79impl<T: Clone + PartialEq + 'static> ListChangeSetSource for Rc<dyn IObservableList<T>> {
80 type Item = T;
81
82 fn source_change_sets(&self) -> Rc<dyn IObservable<ChangeSet<T>>> {
83 self.connect()
84 }
85}
86
87impl<T: Clone + PartialEq + 'static> ListChangeSetSource for Rc<dyn ISourceList<T>> {
88 type Item = T;
89
90 fn source_change_sets(&self) -> Rc<dyn IObservable<ChangeSet<T>>> {
91 self.connect()
92 }
93}
94
95impl<T> PartialEq for dyn IObservableList<T> {
97 fn eq(&self, other: &Self) -> bool {
98 std::ptr::addr_eq(self as *const Self, other as *const Self)
99 }
100}
101
102impl<T: Clone + PartialEq> PartialEq for dyn ISourceList<T> {
104 fn eq(&self, other: &Self) -> bool {
105 std::ptr::addr_eq(self as *const Self, other as *const Self)
106 }
107}
108
109pub trait ListSourcesCombineEx {
113 type Item: Clone + PartialEq + 'static;
115
116 fn and_list(&self) -> Rc<dyn IObservable<ChangeSet<Self::Item>>>
118 where
119 Self::Item: Eq + Hash;
120
121 fn or(&self) -> Rc<dyn IObservable<ChangeSet<Self::Item>>>
123 where
124 Self::Item: Eq + Hash;
125
126 fn xor(&self) -> Rc<dyn IObservable<ChangeSet<Self::Item>>>
128 where
129 Self::Item: Eq + Hash;
130
131 fn except(&self) -> Rc<dyn IObservable<ChangeSet<Self::Item>>>
133 where
134 Self::Item: Eq + Hash;
135}
136
137fn combine_collection<S: ListChangeSetSource>(sources: &[S], kind: CombineOperator) -> Rc<dyn IObservable<ChangeSet<S::Item>>>
139where
140 S::Item: Eq + Hash,
141{
142 combiner(sources.iter().map(ListChangeSetSource::source_change_sets).collect(), kind)
143}
144
145impl<S: ListChangeSetSource> ListSourcesCombineEx for [S] {
146 type Item = S::Item;
147
148 fn and_list(&self) -> Rc<dyn IObservable<ChangeSet<S::Item>>>
149 where
150 Self::Item: Eq + Hash,
151 {
152 combine_collection(self, CombineOperator::And)
153 }
154
155 fn or(&self) -> Rc<dyn IObservable<ChangeSet<S::Item>>>
156 where
157 Self::Item: Eq + Hash,
158 {
159 combine_collection(self, CombineOperator::Or)
160 }
161
162 fn xor(&self) -> Rc<dyn IObservable<ChangeSet<S::Item>>>
163 where
164 Self::Item: Eq + Hash,
165 {
166 combine_collection(self, CombineOperator::Xor)
167 }
168
169 fn except(&self) -> Rc<dyn IObservable<ChangeSet<S::Item>>>
170 where
171 Self::Item: Eq + Hash,
172 {
173 combine_collection(self, CombineOperator::Except)
174 }
175}
176
177pub trait ListSourceListCombineEx {
182 type Item: Clone + PartialEq + 'static;
184
185 fn and_list(&self) -> Rc<dyn IObservable<ChangeSet<Self::Item>>>
188 where
189 Self::Item: Eq + Hash;
190
191 fn or(&self) -> Rc<dyn IObservable<ChangeSet<Self::Item>>>
193 where
194 Self::Item: Eq + Hash;
195
196 fn xor(&self) -> Rc<dyn IObservable<ChangeSet<Self::Item>>>
198 where
199 Self::Item: Eq + Hash;
200
201 fn except(&self) -> Rc<dyn IObservable<ChangeSet<Self::Item>>>
204 where
205 Self::Item: Eq + Hash;
206}
207
208fn combine_list<S: ListChangeSetSource + Clone + PartialEq>(list: &dyn IObservableList<S>, kind: CombineOperator) -> Rc<dyn IObservable<ChangeSet<S::Item>>>
210where
211 S::Item: Eq + Hash,
212{
213 dynamic_combiner(list.connect(), Rc::new(|source: &S| source.source_change_sets()), kind)
214}
215
216macro_rules! list_source_list_combine_impl {
218 ($list:ident) => {
219 impl<S: ListChangeSetSource + Clone + PartialEq> ListSourceListCombineEx for $list<S> {
220 type Item = S::Item;
221
222 fn and_list(&self) -> Rc<dyn IObservable<ChangeSet<S::Item>>>
223 where
224 Self::Item: Eq + Hash,
225 {
226 combine_list(self, CombineOperator::And)
227 }
228
229 fn or(&self) -> Rc<dyn IObservable<ChangeSet<S::Item>>>
230 where
231 Self::Item: Eq + Hash,
232 {
233 combine_list(self, CombineOperator::Or)
234 }
235
236 fn xor(&self) -> Rc<dyn IObservable<ChangeSet<S::Item>>>
237 where
238 Self::Item: Eq + Hash,
239 {
240 combine_list(self, CombineOperator::Xor)
241 }
242
243 fn except(&self) -> Rc<dyn IObservable<ChangeSet<S::Item>>>
244 where
245 Self::Item: Eq + Hash,
246 {
247 combine_list(self, CombineOperator::Except)
248 }
249 }
250 };
251}
252
253list_source_list_combine_impl!(SourceList);
254list_source_list_combine_impl!(ObservableList);