eyeball_im/vector/
entry.rs

1use std::{fmt, ops::Deref};
2
3use super::ObservableVector;
4
5/// A handle to a single value in an [`ObservableVector`].
6pub struct ObservableVectorEntry<'a, T> {
7    inner: &'a mut ObservableVector<T>,
8    index: EntryIndex<'a>,
9}
10
11impl<'a, T> ObservableVectorEntry<'a, T>
12where
13    T: Clone + 'static,
14{
15    pub(super) fn new(inner: &'a mut ObservableVector<T>, index: usize) -> Self {
16        Self { inner, index: EntryIndex::Owned(index) }
17    }
18
19    fn new_borrowed(inner: &'a mut ObservableVector<T>, index: &'a mut usize) -> Self {
20        Self { inner, index: EntryIndex::Borrowed(index) }
21    }
22
23    /// Get the index of the element this `ObservableVectorEntry` refers to.
24    pub fn index(this: &Self) -> usize {
25        this.index.value()
26    }
27
28    /// Replace the given element, notify subscribers and return the previous
29    /// element.
30    pub fn set(this: &mut Self, value: T) -> T {
31        this.inner.set(this.index.value(), value)
32    }
33
34    /// Remove the given element, notify subscribers and return the element.
35    pub fn remove(mut this: Self) -> T {
36        this.inner.remove(this.index.make_owned())
37    }
38}
39
40impl<T> fmt::Debug for ObservableVectorEntry<'_, T>
41where
42    T: fmt::Debug,
43{
44    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
45        let index = self.index.value();
46        f.debug_struct("ObservableVectorEntry")
47            .field("item", &self.inner[index])
48            .field("index", &index)
49            .finish()
50    }
51}
52
53impl<T> Deref for ObservableVectorEntry<'_, T> {
54    type Target = T;
55
56    fn deref(&self) -> &Self::Target {
57        &self.inner[self.index.value()]
58    }
59}
60
61impl<T> Drop for ObservableVectorEntry<'_, T> {
62    fn drop(&mut self) {
63        // If there is an association with an externally-stored index, that
64        // index must be incremented on drop. This allows an external iterator
65        // that produces ObservableVectorEntry items to advance conditionally.
66        //
67        // There are two cases this branch is not hit:
68        //
69        // - make_owned was previously called (used for removing the item and resuming
70        //   iteration with the same index)
71        // - the ObservableVectorEntry was created with ObservableVector::entry, i.e.
72        //   it's not used for iteration at all
73        if let EntryIndex::Borrowed(idx) = &mut self.index {
74            **idx += 1;
75        }
76    }
77}
78
79pub(super) enum EntryIndex<'a> {
80    Borrowed(&'a mut usize),
81    Owned(usize),
82}
83
84impl EntryIndex<'_> {
85    pub(super) fn value(&self) -> usize {
86        match self {
87            EntryIndex::Borrowed(idx) => **idx,
88            EntryIndex::Owned(idx) => *idx,
89        }
90    }
91
92    /// Remove the association with the externally-stored index, if any.
93    ///
94    /// Returns the index value for convenience.
95    pub(super) fn make_owned(&mut self) -> usize {
96        match self {
97            EntryIndex::Borrowed(idx) => {
98                let idx = **idx;
99                *self = EntryIndex::Owned(idx);
100                idx
101            }
102            EntryIndex::Owned(idx) => *idx,
103        }
104    }
105}
106
107/// An "iterator"¹ that yields entries into an [`ObservableVector`].
108///
109/// ¹ conceptually, though it does not implement `std::iterator::Iterator`
110#[derive(Debug)]
111pub struct ObservableVectorEntries<'a, T> {
112    inner: &'a mut ObservableVector<T>,
113    index: usize,
114}
115
116impl<'a, T> ObservableVectorEntries<'a, T>
117where
118    T: Clone + 'static,
119{
120    pub(super) fn new(inner: &'a mut ObservableVector<T>) -> Self {
121        Self { inner, index: 0 }
122    }
123
124    /// Advance this iterator, yielding an `ObservableVectorEntry` for the next
125    /// item in the vector, or `None` if all items have been visited.
126    #[allow(clippy::should_implement_trait)]
127    pub fn next(&mut self) -> Option<ObservableVectorEntry<'_, T>> {
128        if self.index < self.inner.len() {
129            Some(ObservableVectorEntry::new_borrowed(self.inner, &mut self.index))
130        } else {
131            None
132        }
133    }
134}