1use core::marker::PhantomData;
2use core::mem;
3use core::ptr::{drop_in_place, read, NonNull};
4
5extern crate alloc;
6
7use 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)]
22pub 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)]
30pub 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
43impl<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
121unsafe impl<ContainedIn, Owner, DependentStatic> Send
122 for UnsafeSelfCell<ContainedIn, Owner, DependentStatic>
123where
124 // Only derive Send if Owner and DependentStatic is also Send
125 Owner: Send,
126 DependentStatic: Send,
127{
128}
129
130unsafe impl<ContainedIn, Owner, DependentStatic> Sync
131 for UnsafeSelfCell<ContainedIn, Owner, DependentStatic>
132where
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)]
144pub struct OwnerAndCellDropGuard<Owner, Dependent> {
145 joined_ptr: NonNull<JoinedCell<Owner, Dependent>>,
146}
147
148impl<Owner, Dependent> OwnerAndCellDropGuard<Owner, Dependent> {
149 pub unsafe fn new(joined_ptr: NonNull<JoinedCell<Owner, Dependent>>) -> Self {
150 Self { joined_ptr }
151 }
152}
153
154impl<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.
193impl<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