weak_lists/
unsync.rs

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