weak_lists/
sync.rs

1//! The thread-safe version of the list.
2
3mod element;
4mod iter;
5mod list;
6#[cfg(test)]
7mod tests;
8
9use {
10    alloc::sync::{Arc, Weak},
11    core::ops::Range,
12    parking_lot::Mutex,
13    stable_map::StableMap,
14};
15
16/// A thread-safe list holding weak references to its elements.
17///
18/// The list does not hold strong references to its elements and the elements do not hold
19/// strong references to the list. You must use some other mechanism to keep all parties
20/// alive.
21///
22/// This list supports concurrent iteration and modification.
23///
24/// # Examples
25///
26/// ```
27/// use std::sync::Arc;
28/// use {
29///     weak_lists::{SyncWeakList, SyncWeakListElement},
30///     std::{
31///         array,
32///     },
33/// };
34///
35/// pub struct Service {
36///     callbacks: SyncWeakList<dyn Callback>,
37/// }
38///
39/// pub trait Callback {
40///     fn run(&self);
41/// }
42///
43/// impl Service {
44///     pub fn register_callback(&self, callback: &SyncWeakListElement<dyn Callback>) {
45///         callback.attach(&self.callbacks);
46///     }
47///
48///     pub fn run_callbacks(&self) {
49///         for callback in &self.callbacks {
50///             callback.run();
51///         }
52///     }
53/// }
54///
55/// struct Client {
56///     id: usize,
57///     entry: SyncWeakListElement<dyn Callback>,
58/// }
59///
60/// impl Callback for Client {
61///     fn run(&self) {
62///         eprintln!("Callback {} invoked", self.id);
63///         if self.id == 1 {
64///             self.entry.detach();
65///         }
66///     }
67/// }
68///
69/// let service = Service {
70///     callbacks: Default::default(),
71/// };
72/// let clients = array::from_fn::<_, 3, _>(|id| {
73///     Arc::<Client>::new_cyclic(|slf| Client {
74///         id,
75///         entry: SyncWeakListElement::new(slf.clone()),
76///     })
77/// });
78/// for client in &clients {
79///     service.register_callback(&client.entry);
80/// }
81/// service.run_callbacks();
82/// // Callback 0 invoked
83/// // Callback 1 invoked
84/// // Callback 2 invoked
85/// service.run_callbacks();
86/// // Callback 0 invoked
87/// // Callback 2 invoked
88/// ```
89pub struct SyncWeakList<T>
90where
91    T: ?Sized,
92{
93    data: Arc<Mutex<WeakListData<T>>>,
94}
95
96struct WeakListData<T>
97where
98    T: ?Sized,
99{
100    next_id: u64,
101    active_iterators: usize,
102    members: StableMap<u64, Weak<T>>,
103}
104
105/// An thread-safe element that can be inserted into a weak list.
106///
107/// Each element can be attached to 0 or 1 list. Attaching it to a list automatically
108/// detaches itself from the previous list.
109///
110/// When this object is dropped, it detaches itself from its current list.
111pub struct SyncWeakListElement<T>
112where
113    T: ?Sized,
114{
115    t: Weak<T>,
116    data: Mutex<EntryData<T>>,
117}
118
119struct EntryData<T>
120where
121    T: ?Sized,
122{
123    id: u64,
124    owner: Weak<Mutex<WeakListData<T>>>,
125}
126
127/// An iterator over list elements.
128///
129/// This object is created by calling [iter](SyncWeakList::iter) or by using the
130/// [IntoIterator] implementation of `&SyncWeakList`.
131pub struct Iter<'a, T>
132where
133    T: ?Sized,
134{
135    iter: Range<usize>,
136    data: &'a Mutex<WeakListData<T>>,
137}