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,
//             }
//         })
//     }
// }