1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
use crate::{Event, ObservableCollection, Subscription, VecDiff};
use std::cell::RefCell;
use std::rc::Rc;
///
/// ObservableComposite.
///
/// This is a composite collection of any number of observable collections.
///
pub struct ObservableComposite<T: 'static + Clone> {
sources: Vec<Box<dyn ObservableCollection<T>>>,
changed_event: Rc<RefCell<Event<VecDiff<T>>>>,
_source_changed_event_subscriptions: Vec<Subscription>,
}
impl<T: 'static + Clone> ObservableComposite<T> {
pub fn from(sources: Vec<Box<dyn ObservableCollection<T>>>) -> Self {
let changed_event = Rc::new(RefCell::new(Event::new()));
let mut source_changed_event_subscriptions = Vec::new();
// The collection that keeps track of the lengths of all source collections.
//
// Please note that we need to manually update lengths. We cannot just look
// directly into `sources` to get them. Events in `fui` are asynchronous, so
// we could get different results (different index values in generated events).
// For example in a case of quickly adding two items one by one, we receive
// the event of adding the first one later (when both are already added).
let lengths_rc = Rc::new(RefCell::new(Vec::with_capacity(sources.len())));
for (source_index, source) in sources.iter().enumerate() {
// store source length
lengths_rc.borrow_mut().push(source.len());
let lengths_clone = lengths_rc.clone();
let changed_event_clone = changed_event.clone();
let handler = Box::new(move |changed_args| {
// calculate offset, which is sum of length of all previous sources
let offset: usize = lengths_clone.borrow().iter().take(source_index).sum();
// apply offset to event args and update lengths collection
match changed_args {
VecDiff::Clear {} => {
let number_of_sources = lengths_clone.borrow().len();
let mut lengths = lengths_clone.borrow_mut();
let other_collections_size: usize = (0..number_of_sources)
.filter(|i| *i != source_index)
.map(|i| lengths[i])
.sum();
if other_collections_size == 0 {
changed_event_clone.borrow().emit(VecDiff::Clear {});
} else {
for i in (0..lengths[source_index]).rev() {
changed_event_clone
.borrow()
.emit(VecDiff::RemoveAt { index: offset + i });
}
lengths[source_index] = 0;
}
}
VecDiff::InsertAt { index, value } => {
lengths_clone.borrow_mut()[source_index] += 1;
changed_event_clone.borrow().emit(VecDiff::InsertAt {
index: offset + index,
value,
});
}
VecDiff::RemoveAt { index } => {
let mut lengths = lengths_clone.borrow_mut();
if lengths[source_index] > 0 {
lengths[source_index] -= 1;
changed_event_clone.borrow().emit(VecDiff::RemoveAt {
index: offset + index,
});
}
}
VecDiff::Move {
old_index,
new_index,
} => {
changed_event_clone.borrow().emit(VecDiff::Move {
old_index: offset + old_index,
new_index: offset + new_index,
});
}
VecDiff::Pop {} => {
let mut lengths = lengths_clone.borrow_mut();
if lengths[source_index] > 0 {
let index = lengths[source_index] - 1;
lengths[source_index] -= 1;
changed_event_clone.borrow().emit(VecDiff::RemoveAt {
index: offset + index,
});
}
}
VecDiff::Push { value } => {
let mut lengths = lengths_clone.borrow_mut();
let index = lengths[source_index];
lengths[source_index] += 1;
changed_event_clone.borrow().emit(VecDiff::InsertAt {
index: offset + index,
value,
});
}
};
});
if let Some(subscription) = source.on_changed(handler) {
source_changed_event_subscriptions.push(subscription);
}
}
ObservableComposite {
sources,
changed_event,
_source_changed_event_subscriptions: source_changed_event_subscriptions,
}
}
}
impl<T: 'static + Clone> ObservableCollection<T> for ObservableComposite<T> {
fn len(&self) -> usize {
self.sources.iter().map(|s| s.len()).sum()
}
fn get(&self, index: usize) -> Option<T> {
let mut new_index = index;
for source in self.sources.iter() {
let len = source.len();
if new_index < len {
return source.get(new_index);
} else {
new_index -= len;
}
}
None
}
fn on_changed(&self, mut f: Box<dyn FnMut(VecDiff<T>)>) -> Option<Subscription> {
Some(Subscription::EventSubscription(
self.changed_event
.borrow_mut()
.subscribe(move |args| f(args)),
))
}
}