weak_lists/unsync/
element.rs

1use {
2    crate::unsync::{EntryData, WeakList, WeakListElement},
3    alloc::rc::{Rc, Weak},
4    core::{
5        cell::UnsafeCell,
6        fmt::{Debug, Formatter},
7        mem,
8    },
9};
10
11impl<T> WeakListElement<T>
12where
13    T: ?Sized,
14{
15    /// Creates a new list element.
16    ///
17    /// This object holds a weak reference to the `T`. When this object is dropped, it
18    /// automatically detaches itself from the list it is currently attached to.
19    ///
20    /// Often, this object is directly contained in the `T`:
21    ///
22    /// ```rust
23    /// use std::rc::Rc;
24    /// use weak_lists::WeakListElement;
25    ///
26    /// struct Client {
27    ///     element: WeakListElement<Client>,
28    /// }
29    ///
30    /// let client = Rc::new_cyclic(|slf| Client {
31    ///     element: WeakListElement::new(slf.clone()),
32    /// });
33    /// ```
34    ///
35    /// Since only weak references are stored, this does not create any actual reference
36    /// cycles.
37    pub fn new(t: Weak<T>) -> Self {
38        Self {
39            t,
40            data: UnsafeCell::new(EntryData {
41                id: 0,
42                owner: Default::default(),
43            }),
44        }
45    }
46
47    /// Attaches the list element to a list.
48    ///
49    /// If this object was previously attached to a list, it is automatically detached
50    /// from that list.
51    ///
52    /// The list will only hold on a weak reference to this element and vice versa.
53    ///
54    /// Any existing iterator over the list might or might not see this element, this is
55    /// unspecified.
56    ///
57    /// # Examples
58    ///
59    /// ```rust
60    /// use std::rc::Rc;
61    /// use weak_lists::{WeakList, WeakListElement};
62    ///
63    /// struct Client {
64    ///     element: WeakListElement<Client>,
65    /// }
66    ///
67    /// let clients1 = WeakList::default();
68    ///
69    /// let client = Rc::new_cyclic(|slf| Client {
70    ///     element: WeakListElement::new(slf.clone()),
71    /// });
72    ///
73    /// client.element.attach(&clients1);
74    ///
75    /// assert!(clients1.iter().next().is_some());
76    ///
77    /// let clients2 = WeakList::default();
78    ///
79    /// client.element.attach(&clients2);
80    ///
81    /// assert!(clients1.iter().next().is_none());
82    /// assert!(clients2.iter().next().is_some());
83    /// ```
84    pub fn attach(&self, to: &WeakList<T>) {
85        self.detach();
86        let data = unsafe {
87            // SAFETY:
88            // - While we hold this reference, we do not call any functions that might
89            //   create additional references to self.data. This applies to all code that
90            //   creates references to self.data.
91            // - Therefore, this is an exclusive reference to self.data.
92            // - In particular, the clone call below clones an Rc and is therefore safe.
93            // - The insert call only adds an element to a map and is therefore safe.
94            // - list_data.next_id cannot overflow, therefore the insert call returns none
95            //   and no drop code runs. But even if it did run, it would run after all
96            //   uses of the mutable references have concluded.
97            &mut *self.data.get()
98        };
99        data.owner = Rc::downgrade(&to.data);
100        let list_data = unsafe {
101            // SAFETY: See the previous safety comment.
102            &mut *to.data.get()
103        };
104        data.id = list_data.next_id;
105        list_data.next_id += 1;
106        list_data.members.insert(data.id, self.t.clone());
107    }
108
109    /// Detaches the element from its current list.
110    ///
111    /// # Examples
112    ///
113    /// ```rust
114    /// use std::rc::Rc;
115    /// use weak_lists::{WeakList, WeakListElement};
116    ///
117    /// struct Client {
118    ///     element: WeakListElement<Client>,
119    /// }
120    ///
121    /// let clients = WeakList::default();
122    ///
123    /// let client = Rc::new_cyclic(|slf| Client {
124    ///     element: WeakListElement::new(slf.clone()),
125    /// });
126    ///
127    /// client.element.attach(&clients);
128    ///
129    /// assert!(clients.iter().next().is_some());
130    ///
131    /// client.element.detach();
132    ///
133    /// assert!(clients.iter().next().is_none());
134    /// ```
135    pub fn detach(&self) {
136        let data = unsafe {
137            // SAFETY:
138            // - While we hold this reference, we do not call any functions that might
139            //   create additional references to self.data. This applies to all code that
140            //   creates references to self.data.
141            // - Therefore, this is an exclusive reference to self.data.
142            // - All drop code below runs after the last use of the references has
143            //   concluded. However, even if it did run, it could be shown that that code
144            //   is harmless and does not run any code that depends on T.
145            &mut *self.data.get()
146        };
147        let prev = mem::take(&mut data.owner).upgrade();
148        if let Some(prev) = prev {
149            let list_data = unsafe {
150                // SAFETY: See the previous safety comment.
151                &mut *prev.get()
152            };
153            list_data.members.remove(&data.id);
154        }
155    }
156}
157
158impl<T> Drop for WeakListElement<T>
159where
160    T: ?Sized,
161{
162    fn drop(&mut self) {
163        self.detach();
164    }
165}
166
167impl<T> Debug for WeakListElement<T>
168where
169    T: ?Sized,
170{
171    fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
172        let data = unsafe {
173            // SAFETY:
174            // - While we hold this reference, we do not call any functions that might
175            //   create additional references to self.data. This applies to all code that
176            //   creates references to self.data.
177            // - Therefore, this is an exclusive reference to self.data.
178            &mut *self.data.get()
179        };
180        let owner = data.owner.upgrade();
181        let owner_id = owner.as_ref().map(Rc::as_ptr);
182        f.debug_struct("WeakListElement")
183            .field("list", &owner_id)
184            .finish_non_exhaustive()
185    }
186}