1 use core::future::Future; 2 use core::mem::MaybeUninit; 3 use core::pin::Pin; 4 use core::task::{Context, Poll}; 5 6 /// A wrapper type that tells the compiler that the contents might not be valid. 7 /// 8 /// This is necessary mainly when `T` contains a reference. In that case, the 9 /// compiler will sometimes assume that the reference is always valid; in some 10 /// cases it will assume this even after the destructor of `T` runs. For 11 /// example, when a reference is used as a function argument, then the compiler 12 /// will assume that the reference is valid until the function returns, even if 13 /// the reference is destroyed during the function. When the reference is used 14 /// as part of a self-referential struct, that assumption can be false. Wrapping 15 /// the reference in this type prevents the compiler from making that 16 /// assumption. 17 /// 18 /// # Invariants 19 /// 20 /// The `MaybeUninit` will always contain a valid value until the destructor runs. 21 // 22 // Reference 23 // See <https://users.rust-lang.org/t/unsafe-code-review-semi-owning-weak-rwlock-t-guard/95706> 24 // 25 // TODO: replace this with an official solution once RFC #3336 or similar is available. 26 // <https://github.com/rust-lang/rfcs/pull/3336> 27 #[repr(transparent)] 28 pub(crate) struct MaybeDangling<T>(MaybeUninit<T>); 29 30 impl<T> Drop for MaybeDangling<T> { drop(&mut self)31 fn drop(&mut self) { 32 // Safety: `0` is always initialized. 33 unsafe { core::ptr::drop_in_place(self.0.as_mut_ptr()) }; 34 } 35 } 36 37 impl<T> MaybeDangling<T> { new(inner: T) -> Self38 pub(crate) fn new(inner: T) -> Self { 39 Self(MaybeUninit::new(inner)) 40 } 41 } 42 43 impl<F: Future> Future for MaybeDangling<F> { 44 type Output = F::Output; 45 poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output>46 fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> { 47 // Safety: `0` is always initialized. 48 let fut = unsafe { self.map_unchecked_mut(|this| this.0.assume_init_mut()) }; 49 fut.poll(cx) 50 } 51 } 52 53 #[test] maybedangling_runs_drop()54fn maybedangling_runs_drop() { 55 struct SetOnDrop<'a>(&'a mut bool); 56 57 impl Drop for SetOnDrop<'_> { 58 fn drop(&mut self) { 59 *self.0 = true; 60 } 61 } 62 63 let mut success = false; 64 65 drop(MaybeDangling::new(SetOnDrop(&mut success))); 66 assert!(success); 67 } 68