| 1 | use core::marker::PhantomData; |
| 2 | use core::ptr::NonNull; |
| 3 | |
| 4 | /// Models a reborrow of some unique reference, when you know that the reborrow |
| 5 | /// and all its descendants (i.e., all pointers and references derived from it) |
| 6 | /// will not be used any more at some point, after which you want to use the |
| 7 | /// original unique reference again. |
| 8 | /// |
| 9 | /// The borrow checker usually handles this stacking of borrows for you, but |
| 10 | /// some control flows that accomplish this stacking are too complicated for |
| 11 | /// the compiler to follow. A `DormantMutRef` allows you to check borrowing |
| 12 | /// yourself, while still expressing its stacked nature, and encapsulating |
| 13 | /// the raw pointer code needed to do this without undefined behavior. |
| 14 | pub(super) struct DormantMutRef<'a, T> { |
| 15 | ptr: NonNull<T>, |
| 16 | _marker: PhantomData<&'a mut T>, |
| 17 | } |
| 18 | |
| 19 | unsafe impl<'a, T> Sync for DormantMutRef<'a, T> where &'a mut T: Sync {} |
| 20 | unsafe impl<'a, T> Send for DormantMutRef<'a, T> where &'a mut T: Send {} |
| 21 | |
| 22 | impl<'a, T> DormantMutRef<'a, T> { |
| 23 | /// Capture a unique borrow, and immediately reborrow it. For the compiler, |
| 24 | /// the lifetime of the new reference is the same as the lifetime of the |
| 25 | /// original reference, but you promise to use it for a shorter period. |
| 26 | pub(super) fn new(t: &'a mut T) -> (&'a mut T, Self) { |
| 27 | let ptr = NonNull::from(t); |
| 28 | // SAFETY: we hold the borrow throughout 'a via `_marker`, and we expose |
| 29 | // only this reference, so it is unique. |
| 30 | let new_ref = unsafe { &mut *ptr.as_ptr() }; |
| 31 | (new_ref, Self { ptr, _marker: PhantomData }) |
| 32 | } |
| 33 | |
| 34 | /// Revert to the unique borrow initially captured. |
| 35 | /// |
| 36 | /// # Safety |
| 37 | /// |
| 38 | /// The reborrow must have ended, i.e., the reference returned by `new` and |
| 39 | /// all pointers and references derived from it, must not be used anymore. |
| 40 | pub(super) unsafe fn awaken(self) -> &'a mut T { |
| 41 | // SAFETY: our own safety conditions imply this reference is again unique. |
| 42 | unsafe { &mut *self.ptr.as_ptr() } |
| 43 | } |
| 44 | |
| 45 | /// Borrows a new mutable reference from the unique borrow initially captured. |
| 46 | /// |
| 47 | /// # Safety |
| 48 | /// |
| 49 | /// The reborrow must have ended, i.e., the reference returned by `new` and |
| 50 | /// all pointers and references derived from it, must not be used anymore. |
| 51 | pub(super) unsafe fn reborrow(&mut self) -> &'a mut T { |
| 52 | // SAFETY: our own safety conditions imply this reference is again unique. |
| 53 | unsafe { &mut *self.ptr.as_ptr() } |
| 54 | } |
| 55 | |
| 56 | /// Borrows a new shared reference from the unique borrow initially captured. |
| 57 | /// |
| 58 | /// # Safety |
| 59 | /// |
| 60 | /// The reborrow must have ended, i.e., the reference returned by `new` and |
| 61 | /// all pointers and references derived from it, must not be used anymore. |
| 62 | pub(super) unsafe fn reborrow_shared(&self) -> &'a T { |
| 63 | // SAFETY: our own safety conditions imply this reference is again unique. |
| 64 | unsafe { &*self.ptr.as_ptr() } |
| 65 | } |
| 66 | } |
| 67 | |
| 68 | #[cfg (test)] |
| 69 | mod tests; |
| 70 | |