use core::future::Future; use core::mem::MaybeUninit; use core::pin::Pin; use core::task::{Context, Poll}; /// A wrapper type that tells the compiler that the contents might not be valid. /// /// This is necessary mainly when `T` contains a reference. In that case, the /// compiler will sometimes assume that the reference is always valid; in some /// cases it will assume this even after the destructor of `T` runs. For /// example, when a reference is used as a function argument, then the compiler /// will assume that the reference is valid until the function returns, even if /// the reference is destroyed during the function. When the reference is used /// as part of a self-referential struct, that assumption can be false. Wrapping /// the reference in this type prevents the compiler from making that /// assumption. /// /// # Invariants /// /// The `MaybeUninit` will always contain a valid value until the destructor runs. // // Reference // See // // TODO: replace this with an official solution once RFC #3336 or similar is available. // #[repr(transparent)] pub(crate) struct MaybeDangling(MaybeUninit); impl Drop for MaybeDangling { fn drop(&mut self) { // Safety: `0` is always initialized. unsafe { core::ptr::drop_in_place(self.0.as_mut_ptr()) }; } } impl MaybeDangling { pub(crate) fn new(inner: T) -> Self { Self(MaybeUninit::new(inner)) } } impl Future for MaybeDangling { type Output = F::Output; fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { // Safety: `0` is always initialized. let fut = unsafe { self.map_unchecked_mut(|this| this.0.assume_init_mut()) }; fut.poll(cx) } } #[test] fn maybedangling_runs_drop() { struct SetOnDrop<'a>(&'a mut bool); impl Drop for SetOnDrop<'_> { fn drop(&mut self) { *self.0 = true; } } let mut success = false; drop(MaybeDangling::new(SetOnDrop(&mut success))); assert!(success); }