zng_var/
vec.rs

1use std::ops;
2
3use crate::{VARS, VarUpdateId, VarValue};
4
5/// Represents a [`Vec<T>`] that tracks changes when used inside a variable.
6///
7/// The changes made in the last update are available in [`ObservableVec::changes`].
8///
9/// This struct is designed to be a data source for list presenters, because it tracks
10/// exact changes it enables the implementation of transition animations such as a new
11/// element expanding into place, it also allows the retention of widget state for elements
12/// that did not change.
13///
14/// Changes are logged using the [`VecChange`] enum, note that the enum only tracks indexes at the
15/// moment the change happens, that means that you cannot get the removed items and [`VecChange::Insert`]
16/// must be the last change in an update cycle. If any change is made that invalidates an `Insert` all
17/// changes for the cycle are collapsed to [`VecChange::Clear`], to avoid this try to only `remove`
18/// before `insert`.
19#[derive(Debug, Clone, PartialEq)]
20pub struct ObservableVec<T: VarValue> {
21    list: Vec<T>,
22    changes: VecChanges,
23}
24impl<T: VarValue> Default for ObservableVec<T> {
25    fn default() -> Self {
26        Self::new()
27    }
28}
29impl<T: VarValue> ops::Deref for ObservableVec<T> {
30    type Target = [T];
31
32    fn deref(&self) -> &Self::Target {
33        self.list.deref()
34    }
35}
36impl<T: VarValue> ObservableVec<T> {
37    /// New empty vec.
38    pub const fn new() -> Self {
39        Self {
40            list: vec![],
41            changes: VecChanges::new(),
42        }
43    }
44
45    /// New empty vec with pre-allocated capacity.
46    ///
47    /// See [`Vec::with_capacity`].
48    pub fn with_capacity(capacity: usize) -> Self {
49        Self {
50            list: Vec::with_capacity(capacity),
51            changes: VecChanges::new(),
52        }
53    }
54
55    /// Reserves capacity for at least additional more elements.
56    ///
57    /// See [`Vec::reserve`].
58    pub fn reserve(&mut self, additional: usize) {
59        self.list.reserve(additional);
60    }
61
62    /// Insert the `element` at the `index`.
63    ///
64    /// See [`Vec::insert`].
65    pub fn insert(&mut self, index: usize, element: T) {
66        self.list.insert(index, element);
67        self.changes.inserted(index, 1);
68    }
69
70    /// Insert the `element` at the end of the vec.
71    ///
72    /// See [`Vec::push`].
73    pub fn push(&mut self, element: T) {
74        self.insert(self.len(), element);
75    }
76
77    /// Moves all the elements of `other` into `self`, leaving `other` empty.
78    ///
79    /// See [`Vec::append`].
80    pub fn append(&mut self, other: &mut Vec<T>) {
81        self.changes.inserted(self.list.len(), other.len());
82        self.list.append(other);
83    }
84
85    /// Remove the `index` element.
86    ///
87    /// See [`Vec::remove`].
88    pub fn remove(&mut self, index: usize) -> T {
89        let r = self.list.remove(index);
90        self.changes.removed(index, 1);
91        r
92    }
93
94    /// Remove the last element from the vec.
95    ///
96    /// See [`Vec::pop`].
97    pub fn pop(&mut self) -> Option<T> {
98        if self.is_empty() { None } else { Some(self.remove(self.len() - 1)) }
99    }
100
101    /// Shortens the vector, keeping the first `len` elements and dropping the rest.
102    ///
103    /// See [`Vec::truncate`].
104    pub fn truncate(&mut self, len: usize) {
105        if len < self.len() {
106            let count = self.len() - len;
107            self.changes.removed(len, count);
108        }
109        self.list.truncate(len);
110    }
111
112    /// Removes an element from the vector and returns it.
113    ///
114    /// See [`Vec::swap_remove`].
115    pub fn swap_remove(&mut self, index: usize) -> T {
116        let r = self.list.swap_remove(index);
117
118        self.changes.removed(index, 1);
119        self.changes.moved(self.list.len() - 1, index);
120
121        r
122    }
123
124    /// Removes all elements.
125    ///
126    /// See [`Vec::clear`].
127    pub fn clear(&mut self) {
128        if !self.is_empty() {
129            self.clear();
130            self.changes.cleared();
131        }
132    }
133
134    /// Retains only the elements specified by the predicate, passing a mutable reference to it.
135    ///
136    /// See [`Vec::retain_mut`] for more details.
137    pub fn retain<F>(&mut self, mut f: F)
138    where
139        F: FnMut(&mut T) -> bool,
140    {
141        let mut i = 0;
142
143        self.list.retain_mut(|it| {
144            let retain = f(it);
145            if retain {
146                i += 1;
147            } else {
148                self.changes.removed(i, 1);
149            }
150            retain
151        })
152    }
153
154    /// Removes the specified range from the vector in bulk, returning all removed elements as an iterator.
155    ///
156    /// See [`Vec::drain`].
157    pub fn drain<R>(&mut self, range: R) -> std::vec::Drain<'_, T>
158    where
159        R: ops::RangeBounds<usize>,
160    {
161        let range = std_slice_range(range, ..self.len());
162        let r = self.list.drain(range.clone());
163
164        if !range.is_empty() {
165            self.changes.removed(range.start, range.len());
166        }
167
168        r
169    }
170
171    /// Resizes the Vec in-place so that len is equal to `new_len`.
172    ///
173    /// See [`Vec::resize`].
174    pub fn resize(&mut self, new_len: usize, value: T) {
175        if new_len <= self.len() {
176            self.truncate(new_len);
177        } else {
178            let count = new_len - self.len();
179            self.changes.inserted(self.len(), count);
180            self.list.resize(new_len, value);
181        }
182    }
183
184    /// Clones and appends all elements in a slice to the Vec.
185    ///
186    /// See [`Vec::extend_from_slice`].
187    pub fn extend_from_slice(&mut self, other: &[T]) {
188        if !other.is_empty() {
189            self.changes.inserted(self.len(), other.len());
190        }
191        self.list.extend_from_slice(other);
192    }
193
194    /// Copies elements from `src` range to the end of the vector.
195    pub fn extend_from_within<R>(&mut self, src: R)
196    where
197        R: ops::RangeBounds<usize>,
198    {
199        let src = std_slice_range(src, ..self.len());
200
201        let index = self.len();
202
203        self.list.extend_from_within(src.clone());
204
205        if !src.is_empty() {
206            self.changes.inserted(index, src.len());
207        }
208    }
209
210    /// Move the element `from` index `to` index.
211    ///
212    /// If `from < to` this is the same as `self.insert(to - 1, self.remove(from))`, otherwise
213    /// is the same as `self.insert(to, self.remove(from))`, but the change is tracked
214    /// as a single [`VecChange::Move`].
215    pub fn reinsert(&mut self, from: usize, mut to: usize) {
216        if from != to {
217            if from < to {
218                to -= 1;
219            }
220            let el = self.list.remove(from);
221            self.list.insert(to, el);
222            self.changes.moved(from, to);
223        } else {
224            // assert contained
225            let _ = &self.list[to];
226        }
227    }
228
229    /// Mutate the `index`.
230    ///
231    /// This logs a [`VecChange::Remove`] and [`VecChange::Insert`] for the `index`, if it is valid.
232    pub fn get_mut(&mut self, index: usize) -> Option<&mut T> {
233        let r = self.list.get_mut(index);
234        if r.is_some() {
235            self.changes.removed(index, 1);
236            self.changes.inserted(index, 1);
237        }
238        r
239    }
240
241    /// Mutate the `range`.
242    ///
243    /// This logs a [`VecChange::Remove`] and [`VecChange::Insert`] for the `range`, if it is valid.
244    pub fn slice_mut<R>(&mut self, range: R) -> &mut [T]
245    where
246        R: ops::RangeBounds<usize>,
247    {
248        let range = std_slice_range(range, ..self.len());
249        let r = &mut self.list[range.clone()];
250
251        let count = range.len();
252        if count > 0 {
253            self.changes.removed(range.start, count);
254            self.changes.inserted(range.start, count);
255        }
256
257        r
258    }
259
260    /// Changes applied in the last var update.
261    ///
262    /// If the variable is new and this is empty assume the entire vector was replaced (same as [`VecChange::Clear`]).
263    pub fn changes(&self) -> &[VecChange] {
264        if self.changes.update_id == VARS.update_id() {
265            &self.changes.changes
266        } else {
267            &[]
268        }
269    }
270}
271
272impl<T: VarValue> Extend<T> for ObservableVec<T> {
273    fn extend<I: IntoIterator<Item = T>>(&mut self, iter: I) {
274        let index = self.len();
275        self.list.extend(iter);
276        let count = self.len() - index;
277        if count > 0 {
278            self.changes.inserted(index, count);
279        }
280    }
281}
282impl<T: VarValue> From<Vec<T>> for ObservableVec<T> {
283    fn from(value: Vec<T>) -> Self {
284        Self {
285            list: value,
286            changes: VecChanges::new(),
287        }
288    }
289}
290impl<T: VarValue> From<ObservableVec<T>> for Vec<T> {
291    fn from(value: ObservableVec<T>) -> Self {
292        value.list
293    }
294}
295
296/// Represents a change in a [`ObservableVec`].
297#[derive(Clone, Copy, Debug, PartialEq, Eq)]
298pub enum VecChange {
299    /// Elements removed.
300    Remove {
301        /// Index of the first element removed, at the time of removal.
302        index: usize,
303        /// Number of elements removed.
304        count: usize,
305    },
306    /// Elements inserted.
307    Insert {
308        /// Index of the first element inserted, at the time of insertion.
309        ///
310        /// In [`ObservableVec::changes`] the index and count can be used to select
311        /// the new elements in the vec because if any (re)move is made after insert the
312        /// changes are collapsed to a `Clear`.
313        index: usize,
314        /// Number of elements inserted.
315        count: usize,
316    },
317    /// Element removed an reinserted.
318    Move {
319        /// Index the element was first at.
320        from_index: usize,
321        /// Index the element was reinserted after removal.
322        to_index: usize,
323    },
324    /// All elements removed/replaced.
325    Clear,
326}
327
328#[derive(Debug, PartialEq)]
329struct VecChanges {
330    changes: Vec<VecChange>,
331    update_id: VarUpdateId,
332}
333impl Clone for VecChanges {
334    fn clone(&self) -> Self {
335        let update_id = VARS.update_id();
336        if self.update_id == update_id {
337            Self {
338                changes: self.changes.clone(),
339                update_id,
340            }
341        } else {
342            Self {
343                changes: vec![],
344                update_id,
345            }
346        }
347    }
348}
349impl VecChanges {
350    const fn new() -> Self {
351        Self {
352            changes: vec![],
353            update_id: VarUpdateId::never(),
354        }
355    }
356
357    pub fn inserted(&mut self, i: usize, n: usize) {
358        let update_id = VARS.update_id();
359        if self.update_id != update_id {
360            self.changes.clear();
361            self.changes.push(VecChange::Insert { index: i, count: n });
362            self.update_id = update_id;
363        } else if self.changes != [VecChange::Clear] {
364            if let Some(VecChange::Insert { index, count }) = self.changes.last_mut() {
365                if i >= *index && i <= *index + *count {
366                    // new insert inside previous
367                    *count += n;
368                    return;
369                } else {
370                    // insert indexes need to be patched.
371                    self.changes.clear();
372                    self.changes.push(VecChange::Clear);
373                    return;
374                }
375            }
376            self.changes.push(VecChange::Insert { index: i, count: n });
377        }
378    }
379
380    pub fn moved(&mut self, f: usize, t: usize) {
381        let update_id = VARS.update_id();
382        if self.update_id != update_id {
383            self.changes.clear();
384            self.changes.push(VecChange::Move {
385                from_index: f,
386                to_index: t,
387            });
388            self.update_id = update_id;
389        } else if self.changes != [VecChange::Clear] {
390            self.changes.push(VecChange::Move {
391                from_index: f,
392                to_index: t,
393            });
394        }
395    }
396
397    pub fn removed(&mut self, i: usize, n: usize) {
398        let update_id = VARS.update_id();
399        if self.update_id != update_id {
400            self.changes.clear();
401            self.changes.push(VecChange::Remove { index: i, count: n });
402            self.update_id = update_id;
403        } else if self.changes != [VecChange::Clear] {
404            if let Some(last) = self.changes.last_mut() {
405                match last {
406                    VecChange::Remove { index, count } => {
407                        let s = i;
408                        let e = i + n;
409
410                        if s <= *index && e > *index {
411                            // new remove contains previous remove.
412                            *index = s;
413                            *count += n;
414                            return;
415                        }
416                    }
417                    VecChange::Insert { .. } => {
418                        // insert indexes need to be patched.
419                        self.changes.clear();
420                        self.changes.push(VecChange::Clear);
421                        return;
422                    }
423                    _ => {}
424                }
425            }
426
427            self.changes.push(VecChange::Remove { index: i, count: n });
428        }
429    }
430
431    pub fn cleared(&mut self) {
432        self.changes.clear();
433        self.changes.push(VecChange::Clear);
434        self.update_id = VARS.update_id();
435    }
436}
437
438// See <https://github.com/rust-lang/rust/issues/76393>
439#[track_caller]
440#[must_use]
441fn std_slice_range<R>(range: R, bounds: ops::RangeTo<usize>) -> ops::Range<usize>
442where
443    R: ops::RangeBounds<usize>,
444{
445    let len = bounds.end;
446
447    let start: ops::Bound<&usize> = range.start_bound();
448    let start = match start {
449        ops::Bound::Included(&start) => start,
450        ops::Bound::Excluded(start) => start.checked_add(1).unwrap(),
451        ops::Bound::Unbounded => 0,
452    };
453
454    let end: ops::Bound<&usize> = range.end_bound();
455    let end = match end {
456        ops::Bound::Included(end) => end.checked_add(1).unwrap(),
457        ops::Bound::Excluded(&end) => end,
458        ops::Bound::Unbounded => len,
459    };
460
461    if start > end {
462        panic!("invalid range {start}..{end}");
463    }
464    if end > len {
465        panic!("invalid range {start}..{end}");
466    }
467
468    ops::Range { start, end }
469}