1use std::cell::RefCell;
2use std::rc::Rc;
3
4use crate::{TemplateList, TemplateResult};
5
6use super::*;
7
8pub struct SignalVec<T: 'static> {
12 signal: Signal<RefCell<Vec<T>>>,
13 changes: Rc<RefCell<Vec<VecDiff<T>>>>,
16}
17
18impl<T: 'static> SignalVec<T> {
19 pub fn new() -> Self {
21 Self {
22 signal: Signal::new(RefCell::new(Vec::new())),
23 changes: Rc::new(RefCell::new(Vec::new())),
24 }
25 }
26
27 pub fn with_values(values: Vec<T>) -> Self {
29 Self {
30 signal: Signal::new(RefCell::new(values)),
31 changes: Rc::new(RefCell::new(Vec::new())),
32 }
33 }
34
35 pub fn changes(&self) -> &Rc<RefCell<Vec<VecDiff<T>>>> {
37 &self.changes
38 }
39
40 pub fn inner_signal(&self) -> &Signal<RefCell<Vec<T>>> {
44 &self.signal
45 }
46
47 pub fn replace(&self, values: Vec<T>) {
48 self.add_change(VecDiff::Replace { values });
49
50 self.trigger_and_apply_changes();
51 }
52
53 pub fn insert(&self, index: usize, value: T) {
54 self.add_change(VecDiff::Insert { index, value });
55
56 self.trigger_and_apply_changes();
57 }
58
59 pub fn update(&self, index: usize, value: T) {
60 self.add_change(VecDiff::Update { index, value })
61 }
62
63 pub fn remove(&self, index: usize) {
64 self.add_change(VecDiff::Remove { index });
65
66 self.trigger_and_apply_changes();
67 }
68
69 pub fn swap(&self, index1: usize, index2: usize) {
70 self.add_change(VecDiff::Swap { index1, index2 });
71
72 self.trigger_and_apply_changes();
73 }
74
75 pub fn push(&self, value: T) {
76 self.add_change(VecDiff::Push { value });
77
78 self.trigger_and_apply_changes();
79 }
80
81 pub fn pop(&self) {
82 self.add_change(VecDiff::Pop);
83
84 self.trigger_and_apply_changes();
85 }
86
87 pub fn clear(&self) {
88 self.add_change(VecDiff::Clear);
89
90 self.trigger_and_apply_changes();
91 }
92
93 fn add_change(&self, change: VecDiff<T>) {
94 self.changes.borrow_mut().push(change);
95 }
96
97 fn trigger_and_apply_changes(&self) {
98 self.signal.trigger_subscribers();
99
100 for change in self.changes.take() {
101 change.apply_to_vec(&mut self.signal.get().borrow_mut());
102 }
103 }
104
105 pub fn map<U: Clone>(&self, f: impl Fn(&T) -> U + 'static) -> SignalVec<U> {
123 let signal = self.inner_signal().clone();
124 let changes = Rc::clone(&self.changes());
125 let f = Rc::new(f);
126
127 create_effect_initial(move || {
128 let derived = SignalVec::with_values(
129 signal.get().borrow().iter().map(|value| f(value)).collect(),
130 );
131
132 let effect = {
133 let derived = derived.clone();
134 let signal = signal.clone();
135 move || {
136 signal.get(); for change in changes.borrow().iter() {
138 match change {
139 VecDiff::Replace { values } => {
140 derived.replace(values.iter().map(|value| f(value)).collect())
141 }
142 VecDiff::Insert { index, value } => derived.insert(*index, f(value)),
143 VecDiff::Update { index, value } => derived.update(*index, f(value)),
144 VecDiff::Remove { index } => derived.remove(*index),
145 VecDiff::Swap { index1, index2 } => derived.swap(*index1, *index2),
146 VecDiff::Push { value } => derived.push(f(value)),
147 VecDiff::Pop => derived.pop(),
148 VecDiff::Clear => derived.clear(),
149 }
150 }
151 }
152 };
153
154 (Rc::new(effect), derived)
155 })
156 }
157}
158
159impl SignalVec<TemplateResult> {
160 pub fn template_list(&self) -> TemplateList {
162 TemplateList::from(self.clone())
163 }
164}
165
166impl<T: 'static + Clone> SignalVec<T> {
167 pub fn to_vec(&self) -> Vec<T> {
178 self.signal.get().borrow().clone()
179 }
180}
181
182impl<T: 'static> Default for SignalVec<T> {
183 fn default() -> Self {
184 Self::new()
185 }
186}
187
188impl<T: 'static> Clone for SignalVec<T> {
189 fn clone(&self) -> Self {
190 Self {
191 signal: self.signal.clone(),
192 changes: Rc::clone(&self.changes),
193 }
194 }
195}
196
197#[derive(Debug, Clone, PartialEq, Eq)]
199pub enum VecDiff<T> {
200 Replace { values: Vec<T> },
201 Insert { index: usize, value: T },
202 Update { index: usize, value: T },
203 Remove { index: usize },
204 Swap { index1: usize, index2: usize },
205 Push { value: T },
206 Pop,
207 Clear,
208}
209
210impl<T> VecDiff<T> {
211 pub fn apply_to_vec(self, v: &mut Vec<T>) {
212 match self {
213 VecDiff::Replace { values } => *v = values,
214 VecDiff::Insert { index, value } => v.insert(index, value),
215 VecDiff::Update { index, value } => v[index] = value,
216 VecDiff::Remove { index } => {
217 v.remove(index);
218 }
219 VecDiff::Swap { index1, index2 } => v.swap(index1, index2),
220 VecDiff::Push { value } => v.push(value),
221 VecDiff::Pop => {
222 v.pop();
223 }
224 VecDiff::Clear => v.clear(),
225 }
226 }
227}
228
229#[cfg(test)]
230mod tests {
231 use super::*;
232
233 #[test]
234 fn signal_vec() {
235 let my_vec = SignalVec::new();
236 assert_eq!(*my_vec.inner_signal().get().borrow(), Vec::<i32>::new());
237
238 my_vec.push(3);
239 assert_eq!(*my_vec.inner_signal().get().borrow(), vec![3]);
240
241 my_vec.push(4);
242 assert_eq!(*my_vec.inner_signal().get().borrow(), vec![3, 4]);
243
244 my_vec.pop();
245 assert_eq!(*my_vec.inner_signal().get().borrow(), vec![3]);
246 }
247
248 #[test]
249 fn map() {
250 let my_vec = SignalVec::with_values(vec![1, 2, 3]);
251 let squared = my_vec.map(|x| *x * *x);
252
253 assert_eq!(*squared.inner_signal().get().borrow(), vec![1, 4, 9]);
254
255 my_vec.push(4);
256 assert_eq!(*squared.inner_signal().get().borrow(), vec![1, 4, 9, 16]);
257
258 my_vec.pop();
259 assert_eq!(*squared.inner_signal().get().borrow(), vec![1, 4, 9]);
260 }
261
262 #[test]
263 fn map_chain() {
264 let my_vec = SignalVec::with_values(vec![1, 2, 3]);
265 let squared = my_vec.map(|x| *x * 2);
266 let quadrupled = squared.map(|x| *x * 2);
267
268 assert_eq!(*quadrupled.inner_signal().get().borrow(), vec![4, 8, 12]);
269
270 my_vec.push(4);
271 assert_eq!(
272 *quadrupled.inner_signal().get().borrow(),
273 vec![4, 8, 12, 16]
274 );
275
276 my_vec.pop();
277 assert_eq!(*quadrupled.inner_signal().get().borrow(), vec![4, 8, 12]);
278 }
279
280 #[test]
281 fn map_chain_temporary() {
282 let my_vec = SignalVec::with_values(vec![1, 2, 3]);
283 let quadrupled = my_vec.map(|x| *x * 2).map(|x| *x * 2);
284
285 assert_eq!(*quadrupled.inner_signal().get().borrow(), vec![4, 8, 12]);
286
287 my_vec.push(4);
288 assert_eq!(
289 *quadrupled.inner_signal().get().borrow(),
290 vec![4, 8, 12, 16]
291 );
292
293 my_vec.pop();
294 assert_eq!(*quadrupled.inner_signal().get().borrow(), vec![4, 8, 12]);
295 }
296
297 #[test]
298 fn map_inner_scope() {
299 let my_vec = SignalVec::with_values(vec![1, 2, 3]);
300 let quadrupled;
301
302 let doubled = my_vec.map(|x| *x * 2);
303 assert_eq!(*doubled.inner_signal().get().borrow(), vec![2, 4, 6]);
304
305 quadrupled = doubled.map(|x| *x * 2);
306 assert_eq!(*quadrupled.inner_signal().get().borrow(), vec![4, 8, 12]);
307
308 drop(doubled);
309 assert_eq!(*quadrupled.inner_signal().get().borrow(), vec![4, 8, 12]);
310
311 my_vec.push(4);
312 assert_eq!(
313 *quadrupled.inner_signal().get().borrow(),
314 vec![4, 8, 12, 16]
315 );
316 }
317}