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
use std::{fmt, ops::Deref};

use super::ObservableVector;

/// A handle to a single value in an [`ObservableVector`].
pub struct ObservableVectorEntry<'a, T> {
    inner: &'a mut ObservableVector<T>,
    index: EntryIndex<'a>,
}

impl<'a, T> ObservableVectorEntry<'a, T>
where
    T: Clone + Send + Sync + 'static,
{
    pub(super) fn new(inner: &'a mut ObservableVector<T>, index: usize) -> Self {
        Self { inner, index: EntryIndex::Owned(index) }
    }

    fn new_borrowed(inner: &'a mut ObservableVector<T>, index: &'a mut usize) -> Self {
        Self { inner, index: EntryIndex::Borrowed(index) }
    }

    /// Get the index of the element this `ObservableVectorEntry` refers to.
    pub fn index(this: &Self) -> usize {
        this.index.value()
    }

    /// Replace the given element, notify subscribers and return the previous
    /// element.
    pub fn set(this: &mut Self, value: T) -> T {
        this.inner.set(this.index.value(), value)
    }

    /// Remove the given element, notify subscribers and return the element.
    pub fn remove(mut this: Self) -> T {
        this.inner.remove(this.index.make_owned())
    }
}

impl<T> fmt::Debug for ObservableVectorEntry<'_, T>
where
    T: fmt::Debug,
{
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        let index = self.index.value();
        f.debug_struct("ObservableVectorEntry")
            .field("item", &self.inner[index])
            .field("index", &index)
            .finish()
    }
}

impl<T> Deref for ObservableVectorEntry<'_, T> {
    type Target = T;

    fn deref(&self) -> &Self::Target {
        &self.inner[self.index.value()]
    }
}

impl<T> Drop for ObservableVectorEntry<'_, T> {
    fn drop(&mut self) {
        // If there is an association with an externally-stored index, that
        // index must be incremented on drop. This allows an external iterator
        // that produces ObservableVectorEntry items to advance conditionally.
        //
        // There are two cases this branch is not hit:
        //
        // - make_owned was previously called (used for removing the item and resuming
        //   iteration with the same index)
        // - the ObservableVectorEntry was created with ObservableVector::entry, i.e.
        //   it's not used for iteration at all
        if let EntryIndex::Borrowed(idx) = &mut self.index {
            **idx += 1;
        }
    }
}

pub(super) enum EntryIndex<'a> {
    Borrowed(&'a mut usize),
    Owned(usize),
}

impl<'a> EntryIndex<'a> {
    pub(super) fn value(&self) -> usize {
        match self {
            EntryIndex::Borrowed(idx) => **idx,
            EntryIndex::Owned(idx) => *idx,
        }
    }

    /// Remove the association with the externally-stored index, if any.
    ///
    /// Returns the index value for convenience.
    pub(super) fn make_owned(&mut self) -> usize {
        match self {
            EntryIndex::Borrowed(idx) => {
                let idx = **idx;
                *self = EntryIndex::Owned(idx);
                idx
            }
            EntryIndex::Owned(idx) => *idx,
        }
    }
}

/// An "iterator"¹ that yields entries into an [`ObservableVector`].
///
/// ¹ conceptually, though it does not implement `std::iterator::Iterator`
#[derive(Debug)]
pub struct ObservableVectorEntries<'a, T> {
    inner: &'a mut ObservableVector<T>,
    index: usize,
}

impl<'a, T> ObservableVectorEntries<'a, T>
where
    T: Clone + Send + Sync + 'static,
{
    pub(super) fn new(inner: &'a mut ObservableVector<T>) -> Self {
        Self { inner, index: 0 }
    }

    /// Advance this iterator, yielding an `ObservableVectorEntry` for the next
    /// item in the vector, or `None` if all items have been visited.
    #[allow(clippy::should_implement_trait)]
    pub fn next(&mut self) -> Option<ObservableVectorEntry<'_, T>> {
        if self.index < self.inner.len() {
            Some(ObservableVectorEntry::new_borrowed(self.inner, &mut self.index))
        } else {
            None
        }
    }
}