zng_var/
vec.rs

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