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
use std::sync::atomic::{AtomicUsize, Ordering};
use std::sync::Arc;
/// A dynamic index that updates automatically when items are shifted inside a factory container.
///
/// For example a [`FactoryVecDeque`](super::FactoryVecDeque) has an [`insert`](super::FactoryVecDequeGuard::insert)
/// method that allows users to insert data at arbitrary positions.
/// If we insert at the front all following widgets will be moved by one which would
/// invalidate their indices.
/// To allow widgets in a factory container to send messages with valid indices
/// this type ensures that the indices is always up to date.
///
/// Never send an index as [`usize`] but always as [`DynamicIndex`]
/// to the update function because messages can be queued up and stale by the time they are handled.
///
/// [`DynamicIndex`] is a smart pointer so cloning will work similar to [`std::rc::Rc`] and will create
/// a pointer to the same data.
///
/// In short: only call [`current_index`](DynamicIndex::current_index) from the update function
/// where you actually need the index as [`usize`].
#[derive(Debug)]
pub struct DynamicIndex {
inner: Arc<AtomicUsize>,
}
impl PartialEq for DynamicIndex {
fn eq(&self, other: &Self) -> bool {
self.current_index().eq(&other.current_index())
}
}
impl Eq for DynamicIndex {}
impl Clone for DynamicIndex {
fn clone(&self) -> Self {
Self {
inner: self.inner.clone(),
}
}
}
impl DynamicIndex {
/// Get the current index number.
///
/// This value is updated by the factory container and might change after each update function.
#[must_use]
pub fn current_index(&self) -> usize {
self.inner.load(Ordering::Relaxed)
}
// Creates a [`WeakDynamicIndex`] for sending in messages.
// pub fn downgrade(&self) -> WeakDynamicIndex {
// WeakDynamicIndex {
// inner: Arc::downgrade(&self.inner),
// }
// }
pub(super) fn increment(&self) {
self.inner.fetch_add(1, Ordering::Relaxed);
}
pub(super) fn decrement(&self) {
self.inner.fetch_sub(1, Ordering::Relaxed);
}
pub(super) fn set_value(&self, new_value: usize) {
self.inner.store(new_value, Ordering::Relaxed);
}
pub(super) fn new(index: usize) -> Self {
Self {
inner: Arc::new(AtomicUsize::new(index)),
}
}
}
// A weak version of [`DynamicIndex`].
//
// Use this to send messages to the update function and call [`upgrade`](WeakDynamicIndex::upgrade)
// to receive the actual [`DynamicIndex`].
//
// A weak index is preferred for sending in messages because messages can be stale by the time they
// are handled and the element already deleted. A weak reference doesn't keep the index alive
// if the element was deleted which allows you to properly handle invalid indices.
//
// # Panics
//
// Sending a [`WeakDynamicIndex`] to a different thread and accessing it will panic.
// #[derive(Debug)]
// pub struct WeakDynamicIndex {
// inner: Weak<Mutex<usize>>,
// }
// impl Clone for WeakDynamicIndex {
// fn clone(&self) -> Self {
// WeakDynamicIndex {
// inner: self.inner.clone(),
// }
// }
// }
// impl WeakDynamicIndex {
// Attempts to upgrade the [`WeakDynamicIndex`] to a [`DynamicIndex`].
//
// Returns [`None`] if the index has since been dropped.
// pub fn upgrade(&self) -> Option<DynamicIndex> {
// Weak::upgrade(&self.inner).map(|inner| {
// DynamicIndex {
// inner,
// }
// })
// }
// }