• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 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.
new(t: &'a mut T) -> (&'a mut T, Self)26     pub 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.
awaken(self) -> &'a mut T40     pub 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.
reborrow(&mut self) -> &'a mut T51     pub 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.
reborrow_shared(&self) -> &'a T62     pub 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