1 | #![allow (clippy::missing_safety_doc, clippy::needless_lifetimes)] |
2 | |
3 | use core::cell::UnsafeCell; |
4 | use core::marker::PhantomData; |
5 | use core::mem; |
6 | use core::ptr::{drop_in_place, read, NonNull}; |
7 | use core::sync::atomic::{AtomicBool, Ordering}; |
8 | |
9 | extern crate alloc; |
10 | |
11 | use alloc::alloc::{dealloc, Layout}; |
12 | |
13 | // Self referential structs are currently not supported with safe vanilla Rust. |
14 | // The only reasonable safe alternative is to expect the user to juggle 2 separate |
15 | // data structures which is a mess. The library solution rental is both no longer |
16 | // maintained and really heavy to compile. So begrudgingly I rolled my own version. |
17 | // These are some of the core invariants we require for this to be safe to use. |
18 | // |
19 | // 1. owner is initialized when UnsafeSelfCell is constructed. |
20 | // 2. owner is NEVER changed again. |
21 | // 3. The pointer to owner and dependent never changes, even when moved. |
22 | // 4. The only access to owner and dependent is as immutable reference. |
23 | // 5. owner lives longer than dependent. |
24 | |
25 | #[doc (hidden)] |
26 | pub struct JoinedCell<Owner, Dependent> { |
27 | pub owner: Owner, |
28 | pub dependent: Dependent, |
29 | } |
30 | |
31 | // Library controlled struct that marks all accesses as unsafe. |
32 | // Because the macro generated struct impl can be extended, could be unsafe. |
33 | #[doc (hidden)] |
34 | pub struct UnsafeSelfCell<ContainedIn, Owner, DependentStatic: 'static> { |
35 | joined_void_ptr: NonNull<u8>, |
36 | |
37 | // ContainedIn is necessary for type safety since we don't fully |
38 | // prohibit access to the UnsafeSelfCell; swapping between different |
39 | // structs can be unsafe otherwise, see Issue #17. |
40 | contained_in_marker: PhantomData<ContainedIn>, |
41 | |
42 | owner_marker: PhantomData<Owner>, |
43 | // DependentStatic is only used to correctly derive Send and Sync. |
44 | dependent_marker: PhantomData<DependentStatic>, |
45 | } |
46 | |
47 | impl<ContainedIn, Owner, DependentStatic> UnsafeSelfCell<ContainedIn, Owner, DependentStatic> { |
48 | pub unsafe fn new(joined_void_ptr: NonNull<u8>) -> Self { |
49 | Self { |
50 | joined_void_ptr, |
51 | contained_in_marker: PhantomData, |
52 | owner_marker: PhantomData, |
53 | dependent_marker: PhantomData, |
54 | } |
55 | } |
56 | |
57 | // Calling any of these *unsafe* functions with the wrong Dependent type is UB. |
58 | |
59 | pub unsafe fn borrow_owner<'a, Dependent>(&'a self) -> &'a Owner { |
60 | let joined_ptr = self.joined_void_ptr.cast::<JoinedCell<Owner, Dependent>>(); |
61 | |
62 | &(*joined_ptr.as_ptr()).owner |
63 | } |
64 | |
65 | pub unsafe fn borrow_dependent<'a, Dependent>(&'a self) -> &'a Dependent { |
66 | let joined_ptr = self.joined_void_ptr.cast::<JoinedCell<Owner, Dependent>>(); |
67 | |
68 | &(*joined_ptr.as_ptr()).dependent |
69 | } |
70 | |
71 | pub unsafe fn borrow_mut<'a, Dependent>(&'a mut self) -> (&'a Owner, &'a mut Dependent) { |
72 | let joined_ptr = self.joined_void_ptr.cast::<JoinedCell<Owner, Dependent>>(); |
73 | |
74 | // This function used to return `&'a mut JoinedCell<Owner, Dependent>`. |
75 | // It now creates two references to the fields instead to avoid claiming mutable access |
76 | // to the whole `JoinedCell` (including the owner!) here. |
77 | ( |
78 | &(*joined_ptr.as_ptr()).owner, |
79 | &mut (*joined_ptr.as_ptr()).dependent, |
80 | ) |
81 | } |
82 | |
83 | // Any subsequent use of this struct other than dropping it is UB. |
84 | pub unsafe fn drop_joined<Dependent>(&mut self) { |
85 | let joined_ptr = self.joined_void_ptr.cast::<JoinedCell<Owner, Dependent>>(); |
86 | |
87 | // Also used in case drop_in_place(...dependent) fails |
88 | let _guard = OwnerAndCellDropGuard { joined_ptr }; |
89 | |
90 | // IMPORTANT dependent must be dropped before owner. |
91 | // We don't want to rely on an implicit order of struct fields. |
92 | // So we drop the struct, field by field manually. |
93 | drop_in_place(&mut (*joined_ptr.as_ptr()).dependent); |
94 | |
95 | // Dropping owner |
96 | // and deallocating |
97 | // due to _guard at end of scope. |
98 | } |
99 | |
100 | pub unsafe fn into_owner<Dependent>(self) -> Owner { |
101 | let joined_ptr = self.joined_void_ptr.cast::<JoinedCell<Owner, Dependent>>(); |
102 | |
103 | // In case drop_in_place(...dependent) fails |
104 | let drop_guard = OwnerAndCellDropGuard::new(joined_ptr); |
105 | |
106 | // Drop dependent |
107 | drop_in_place(&mut (*joined_ptr.as_ptr()).dependent); |
108 | |
109 | mem::forget(drop_guard); |
110 | |
111 | let owner_ptr: *const Owner = &(*joined_ptr.as_ptr()).owner; |
112 | |
113 | // Move owner out so it can be returned. |
114 | // Must not read before dropping dependent!! (Which happened above.) |
115 | let owner = read(owner_ptr); |
116 | |
117 | // Deallocate JoinedCell |
118 | let layout = Layout::new::<JoinedCell<Owner, Dependent>>(); |
119 | dealloc(self.joined_void_ptr.as_ptr(), layout); |
120 | |
121 | owner |
122 | } |
123 | } |
124 | |
125 | unsafe impl<ContainedIn, Owner, DependentStatic> Send |
126 | for UnsafeSelfCell<ContainedIn, Owner, DependentStatic> |
127 | where |
128 | // Only derive Send if Owner and DependentStatic is also Send |
129 | Owner: Send, |
130 | DependentStatic: Send, |
131 | { |
132 | } |
133 | |
134 | unsafe impl<ContainedIn, Owner, DependentStatic> Sync |
135 | for UnsafeSelfCell<ContainedIn, Owner, DependentStatic> |
136 | where |
137 | // Only derive Sync if Owner and DependentStatic is also Sync |
138 | Owner: Sync, |
139 | DependentStatic: Sync, |
140 | { |
141 | } |
142 | |
143 | // This struct is used to safely deallocate only the owner if dependent |
144 | // construction fails. |
145 | // |
146 | // mem::forget it once it's no longer needed or dtor will be UB. |
147 | #[doc (hidden)] |
148 | pub struct OwnerAndCellDropGuard<Owner, Dependent> { |
149 | joined_ptr: NonNull<JoinedCell<Owner, Dependent>>, |
150 | } |
151 | |
152 | impl<Owner, Dependent> OwnerAndCellDropGuard<Owner, Dependent> { |
153 | pub unsafe fn new(joined_ptr: NonNull<JoinedCell<Owner, Dependent>>) -> Self { |
154 | Self { joined_ptr } |
155 | } |
156 | } |
157 | |
158 | impl<Owner, Dependent> Drop for OwnerAndCellDropGuard<Owner, Dependent> { |
159 | fn drop(&mut self) { |
160 | struct DeallocGuard { |
161 | ptr: *mut u8, |
162 | layout: Layout, |
163 | } |
164 | impl Drop for DeallocGuard { |
165 | fn drop(&mut self) { |
166 | unsafe { dealloc(self.ptr, self.layout) } |
167 | } |
168 | } |
169 | |
170 | // Deallocate even when the drop_in_place(...owner) panics |
171 | let _guard = DeallocGuard { |
172 | ptr: self.joined_ptr.as_ptr() as *mut u8, |
173 | layout: Layout::new::<JoinedCell<Owner, Dependent>>(), |
174 | }; |
175 | |
176 | unsafe { |
177 | // We must only drop owner and the struct itself, |
178 | // The whole point of this drop guard is to clean up the partially |
179 | // initialized struct should building the dependent fail. |
180 | drop_in_place(&mut (*self.joined_ptr.as_ptr()).owner); |
181 | } |
182 | |
183 | // Deallocation happens at end of scope |
184 | } |
185 | } |
186 | |
187 | // Older versions of rust do not support addr_of_mut!. What we want to do here |
188 | // is to emulate the behavior of that macro by going (incorrectly) via a |
189 | // reference cast. Technically this is UB, but testing does not show the older |
190 | // compiler versions (ab)using this. For discussions about this behavior see |
191 | // https://github.com/Voultapher/self_cell/pull/31 and |
192 | // https://github.com/Voultapher/self_cell/issues/30 and |
193 | // https://github.com/Voultapher/self_cell/pull/33 |
194 | // |
195 | // Because of 'procedural macros cannot expand to macro definitions' |
196 | // we have wrap this in functions. |
197 | impl<Owner, Dependent> JoinedCell<Owner, Dependent> { |
198 | #[doc (hidden)] |
199 | #[cfg (not(feature = "old_rust" ))] |
200 | pub unsafe fn _field_pointers(this: *mut Self) -> (*mut Owner, *mut Dependent) { |
201 | let owner_ptr = core::ptr::addr_of_mut!((*this).owner); |
202 | let dependent_ptr = core::ptr::addr_of_mut!((*this).dependent); |
203 | |
204 | (owner_ptr, dependent_ptr) |
205 | } |
206 | |
207 | #[doc (hidden)] |
208 | #[cfg (feature = "old_rust" )] |
209 | #[rustversion::since(1.51)] |
210 | pub unsafe fn _field_pointers(this: *mut Self) -> (*mut Owner, *mut Dependent) { |
211 | let owner_ptr = core::ptr::addr_of_mut!((*this).owner); |
212 | let dependent_ptr = core::ptr::addr_of_mut!((*this).dependent); |
213 | |
214 | (owner_ptr, dependent_ptr) |
215 | } |
216 | |
217 | #[doc (hidden)] |
218 | #[cfg (feature = "old_rust" )] |
219 | #[rustversion::before(1.51)] |
220 | pub unsafe fn _field_pointers(this: *mut Self) -> (*mut Owner, *mut Dependent) { |
221 | // See comment above, technically this is UB. |
222 | let owner_ptr = &mut (*this).owner as *mut Owner; |
223 | let dependent_ptr = &mut (*this).dependent as *mut Dependent; |
224 | |
225 | (owner_ptr, dependent_ptr) |
226 | } |
227 | } |
228 | |
229 | /// Wrapper type that allows creating a self-referential type that hold a mutable borrow `&mut T`. |
230 | /// |
231 | /// Example usage: |
232 | /// |
233 | /// ``` |
234 | /// use self_cell::{self_cell, MutBorrow}; |
235 | /// |
236 | /// type MutStringRef<'a> = &'a mut String; |
237 | /// |
238 | /// self_cell!( |
239 | /// struct MutStringCell { |
240 | /// owner: MutBorrow<String>, |
241 | /// |
242 | /// #[covariant] |
243 | /// dependent: MutStringRef, |
244 | /// } |
245 | /// ); |
246 | /// |
247 | /// let mut cell = MutStringCell::new(MutBorrow::new("abc" .into()), |owner| owner.borrow_mut()); |
248 | /// cell.with_dependent_mut(|_owner, dependent| { |
249 | /// assert_eq!(dependent, &"abc" ); |
250 | /// dependent.pop(); |
251 | /// assert_eq!(dependent, &"ab" ); |
252 | /// }); |
253 | /// |
254 | /// let recovered_owner: String = cell.into_owner().into_inner(); |
255 | /// assert_eq!(recovered_owner, "ab" ); |
256 | /// ``` |
257 | pub struct MutBorrow<T> { |
258 | // Private on purpose. |
259 | is_locked: AtomicBool, |
260 | value: UnsafeCell<T>, |
261 | } |
262 | |
263 | impl<T> MutBorrow<T> { |
264 | /// Constructs a new `MutBorrow`. |
265 | pub fn new(value: T) -> Self { |
266 | // Use the Rust type system to model an affine type that can only go from unlocked -> locked |
267 | // but never the other way around. |
268 | Self { |
269 | is_locked: AtomicBool::new(false), |
270 | value: UnsafeCell::new(value), |
271 | } |
272 | } |
273 | |
274 | /// Obtains a mutable reference to the underlying data. |
275 | /// |
276 | /// This function can only sensibly be used in the builder function. Afterwards, it's impossible |
277 | /// to access the inner value, with the exception of [`MutBorrow::into_inner`]. |
278 | /// |
279 | /// # Panics |
280 | /// |
281 | /// Will panic if called anywhere but in the dependent constructor. Will also panic if called |
282 | /// more than once. |
283 | #[allow (clippy::mut_from_ref)] |
284 | pub fn borrow_mut(&self) -> &mut T { |
285 | // Ensure this function can only be called once. |
286 | // Relaxed should be fine, because only one thread could ever read `false` anyway, |
287 | // so further synchronization is pointless. |
288 | let was_locked = self.is_locked.swap(true, Ordering::Relaxed); |
289 | |
290 | if was_locked { |
291 | panic!("Tried to access locked MutBorrow" ) |
292 | } else { |
293 | // SAFETY: `self.is_locked` starts out as locked and can never be unlocked again, which |
294 | // guarantees that this function can only be called once. And the `self.value` being |
295 | // private ensures that there are no other references to it. |
296 | unsafe { &mut *self.value.get() } |
297 | } |
298 | } |
299 | |
300 | /// Consumes `self` and returns the wrapped value. |
301 | pub fn into_inner(self) -> T { |
302 | self.value.into_inner() |
303 | } |
304 | } |
305 | |
306 | // SAFETY: The reasoning why it is safe to share `MutBorrow` across threads is as follows: The |
307 | // `AtomicBool` `is_locked` ensures that only ever exactly one thread can get access to the inner |
308 | // value. In that sense it works like a critical section, that begins when `borrow_mut()` is called |
309 | // and that ends when the outer `MutBorrow` is dropped. Once one thread acquired the unique |
310 | // reference through `borrow_mut()` no other interaction with the inner value MUST ever be possible |
311 | // while the outer `MutBorrow` is alive. |
312 | unsafe impl<T: Send> Sync for MutBorrow<T> {} |
313 | |