eyeball_im/vector/entry.rs
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 + '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 EntryIndex<'_> {
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 + '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
}
}
}