1 | use core::marker::PhantomData; |
2 | use core::mem; |
3 | use core::ptr::{drop_in_place, read, NonNull}; |
4 | |
5 | extern crate alloc; |
6 | |
7 | use alloc::alloc::{dealloc, Layout}; |
8 | |
9 | // Self referential structs are currently not supported with safe vanilla Rust. |
10 | // The only reasonable safe alternative is to expect the user to juggle 2 separate |
11 | // data structures which is a mess. The library solution rental is both no longer |
12 | // maintained and really heavy to compile. So begrudgingly I rolled my own version. |
13 | // These are some of the core invariants we require for this to be safe to use. |
14 | // |
15 | // 1. owner is initialized when UnsafeSelfCell is constructed. |
16 | // 2. owner is NEVER changed again. |
17 | // 3. The pointer to owner and dependent never changes, even when moved. |
18 | // 4. The only access to owner and dependent is as immutable reference. |
19 | // 5. owner lives longer than dependent. |
20 | |
21 | #[doc (hidden)] |
22 | pub struct JoinedCell<Owner, Dependent> { |
23 | pub owner: Owner, |
24 | pub dependent: Dependent, |
25 | } |
26 | |
27 | // Library controlled struct that marks all accesses as unsafe. |
28 | // Because the macro generated struct impl can be extended, could be unsafe. |
29 | #[doc (hidden)] |
30 | pub struct UnsafeSelfCell<ContainedIn, Owner, DependentStatic: 'static> { |
31 | joined_void_ptr: NonNull<u8>, |
32 | |
33 | // ContainedIn is necessary for type safety since we don't fully |
34 | // prohibit access to the UnsafeSelfCell; swapping between different |
35 | // structs can be unsafe otherwise, see Issue #17. |
36 | contained_in_marker: PhantomData<ContainedIn>, |
37 | |
38 | owner_marker: PhantomData<Owner>, |
39 | // DependentStatic is only used to correctly derive Send and Sync. |
40 | dependent_marker: PhantomData<DependentStatic>, |
41 | } |
42 | |
43 | impl<ContainedIn, Owner, DependentStatic> UnsafeSelfCell<ContainedIn, Owner, DependentStatic> { |
44 | pub unsafe fn new(joined_void_ptr: NonNull<u8>) -> Self { |
45 | Self { |
46 | joined_void_ptr, |
47 | contained_in_marker: PhantomData, |
48 | owner_marker: PhantomData, |
49 | dependent_marker: PhantomData, |
50 | } |
51 | } |
52 | |
53 | // Calling any of these *unsafe* functions with the wrong Dependent type is UB. |
54 | |
55 | pub unsafe fn borrow_owner<'a, Dependent>(&'a self) -> &'a Owner { |
56 | let joined_ptr = self.joined_void_ptr.cast::<JoinedCell<Owner, Dependent>>(); |
57 | |
58 | &(*joined_ptr.as_ptr()).owner |
59 | } |
60 | |
61 | pub unsafe fn borrow_dependent<'a, Dependent>(&'a self) -> &'a Dependent { |
62 | let joined_ptr = self.joined_void_ptr.cast::<JoinedCell<Owner, Dependent>>(); |
63 | |
64 | &(*joined_ptr.as_ptr()).dependent |
65 | } |
66 | |
67 | pub unsafe fn borrow_mut<'a, Dependent>(&'a mut self) -> (&'a Owner, &'a mut Dependent) { |
68 | let joined_ptr = self.joined_void_ptr.cast::<JoinedCell<Owner, Dependent>>(); |
69 | |
70 | // This function used to return `&'a mut JoinedCell<Owner, Dependent>`. |
71 | // It now creates two references to the fields instead to avoid claiming mutable access |
72 | // to the whole `JoinedCell` (including the owner!) here. |
73 | ( |
74 | &(*joined_ptr.as_ptr()).owner, |
75 | &mut (*joined_ptr.as_ptr()).dependent, |
76 | ) |
77 | } |
78 | |
79 | // Any subsequent use of this struct other than dropping it is UB. |
80 | pub unsafe fn drop_joined<Dependent>(&mut self) { |
81 | let joined_ptr = self.joined_void_ptr.cast::<JoinedCell<Owner, Dependent>>(); |
82 | |
83 | // Also used in case drop_in_place(...dependent) fails |
84 | let _guard = OwnerAndCellDropGuard { joined_ptr }; |
85 | |
86 | // IMPORTANT dependent must be dropped before owner. |
87 | // We don't want to rely on an implicit order of struct fields. |
88 | // So we drop the struct, field by field manually. |
89 | drop_in_place(&mut (*joined_ptr.as_ptr()).dependent); |
90 | |
91 | // Dropping owner |
92 | // and deallocating |
93 | // due to _guard at end of scope. |
94 | } |
95 | |
96 | pub unsafe fn into_owner<Dependent>(self) -> Owner { |
97 | let joined_ptr = self.joined_void_ptr.cast::<JoinedCell<Owner, Dependent>>(); |
98 | |
99 | // In case drop_in_place(...dependent) fails |
100 | let drop_guard = OwnerAndCellDropGuard::new(joined_ptr); |
101 | |
102 | // Drop dependent |
103 | drop_in_place(&mut (*joined_ptr.as_ptr()).dependent); |
104 | |
105 | mem::forget(drop_guard); |
106 | |
107 | let owner_ptr: *const Owner = &(*joined_ptr.as_ptr()).owner; |
108 | |
109 | // Move owner out so it can be returned. |
110 | // Must not read before dropping dependent!! (Which happened above.) |
111 | let owner = read(owner_ptr); |
112 | |
113 | // Deallocate JoinedCell |
114 | let layout = Layout::new::<JoinedCell<Owner, Dependent>>(); |
115 | dealloc(self.joined_void_ptr.as_ptr(), layout); |
116 | |
117 | owner |
118 | } |
119 | } |
120 | |
121 | unsafe impl<ContainedIn, Owner, DependentStatic> Send |
122 | for UnsafeSelfCell<ContainedIn, Owner, DependentStatic> |
123 | where |
124 | // Only derive Send if Owner and DependentStatic is also Send |
125 | Owner: Send, |
126 | DependentStatic: Send, |
127 | { |
128 | } |
129 | |
130 | unsafe impl<ContainedIn, Owner, DependentStatic> Sync |
131 | for UnsafeSelfCell<ContainedIn, Owner, DependentStatic> |
132 | where |
133 | // Only derive Sync if Owner and DependentStatic is also Sync |
134 | Owner: Sync, |
135 | DependentStatic: Sync, |
136 | { |
137 | } |
138 | |
139 | // This struct is used to safely deallocate only the owner if dependent |
140 | // construction fails. |
141 | // |
142 | // mem::forget it once it's no longer needed or dtor will be UB. |
143 | #[doc (hidden)] |
144 | pub struct OwnerAndCellDropGuard<Owner, Dependent> { |
145 | joined_ptr: NonNull<JoinedCell<Owner, Dependent>>, |
146 | } |
147 | |
148 | impl<Owner, Dependent> OwnerAndCellDropGuard<Owner, Dependent> { |
149 | pub unsafe fn new(joined_ptr: NonNull<JoinedCell<Owner, Dependent>>) -> Self { |
150 | Self { joined_ptr } |
151 | } |
152 | } |
153 | |
154 | impl<Owner, Dependent> Drop for OwnerAndCellDropGuard<Owner, Dependent> { |
155 | fn drop(&mut self) { |
156 | struct DeallocGuard { |
157 | ptr: *mut u8, |
158 | layout: Layout, |
159 | } |
160 | impl Drop for DeallocGuard { |
161 | fn drop(&mut self) { |
162 | unsafe { dealloc(self.ptr, self.layout) } |
163 | } |
164 | } |
165 | |
166 | // Deallocate even when the drop_in_place(...owner) panics |
167 | let _guard = DeallocGuard { |
168 | ptr: self.joined_ptr.as_ptr() as *mut u8, |
169 | layout: Layout::new::<JoinedCell<Owner, Dependent>>(), |
170 | }; |
171 | |
172 | unsafe { |
173 | // We must only drop owner and the struct itself, |
174 | // The whole point of this drop guard is to clean up the partially |
175 | // initialized struct should building the dependent fail. |
176 | drop_in_place(&mut (*self.joined_ptr.as_ptr()).owner); |
177 | } |
178 | |
179 | // Deallocation happens at end of scope |
180 | } |
181 | } |
182 | |
183 | // Older versions of rust do not support addr_of_mut!. What we want to do here |
184 | // is to emulate the behavior of that macro by going (incorrectly) via a |
185 | // reference cast. Technically this is UB, but testing does not show the older |
186 | // compiler versions (ab)using this. For discussions about this behavior see |
187 | // https://github.com/Voultapher/self_cell/pull/31 and |
188 | // https://github.com/Voultapher/self_cell/issues/30 and |
189 | // https://github.com/Voultapher/self_cell/pull/33 |
190 | // |
191 | // Because of 'procedural macros cannot expand to macro definitions' |
192 | // we have wrap this in functions. |
193 | impl<Owner, Dependent> JoinedCell<Owner, Dependent> { |
194 | #[doc (hidden)] |
195 | #[cfg (not(feature = "old_rust" ))] |
196 | pub unsafe fn _field_pointers(this: *mut Self) -> (*mut Owner, *mut Dependent) { |
197 | let owner_ptr = core::ptr::addr_of_mut!((*this).owner); |
198 | let dependent_ptr = core::ptr::addr_of_mut!((*this).dependent); |
199 | |
200 | (owner_ptr, dependent_ptr) |
201 | } |
202 | |
203 | #[doc (hidden)] |
204 | #[cfg (feature = "old_rust" )] |
205 | #[rustversion::since(1.51)] |
206 | pub unsafe fn _field_pointers(this: *mut Self) -> (*mut Owner, *mut Dependent) { |
207 | let owner_ptr = core::ptr::addr_of_mut!((*this).owner); |
208 | let dependent_ptr = core::ptr::addr_of_mut!((*this).dependent); |
209 | |
210 | (owner_ptr, dependent_ptr) |
211 | } |
212 | |
213 | #[doc (hidden)] |
214 | #[cfg (feature = "old_rust" )] |
215 | #[rustversion::before(1.51)] |
216 | pub unsafe fn _field_pointers(this: *mut Self) -> (*mut Owner, *mut Dependent) { |
217 | // See comment above, technically this is UB. |
218 | let owner_ptr = &mut (*this).owner as *mut Owner; |
219 | let dependent_ptr = &mut (*this).dependent as *mut Dependent; |
220 | |
221 | (owner_ptr, dependent_ptr) |
222 | } |
223 | } |
224 | |