| 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 | |