1use core::future::Future;
2use core::mem::MaybeUninit;
3use core::pin::Pin;
4use 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)]
28pub(crate) struct MaybeDangling<T>(MaybeUninit<T>);
29
30impl<T> Drop for MaybeDangling<T> {
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
37impl<T> MaybeDangling<T> {
38 pub(crate) fn new(inner: T) -> Self {
39 Self(MaybeUninit::new(val:inner))
40 }
41}
42
43impl<F: Future> Future for MaybeDangling<F> {
44 type Output = F::Output;
45
46 fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
47 // Safety: `0` is always initialized.
48 let fut: Pin<&mut F> = unsafe { self.map_unchecked_mut(|this: &mut MaybeDangling| this.0.assume_init_mut()) };
49 fut.poll(cx)
50 }
51}
52
53#[test]
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: bool = false;
64
65 drop(MaybeDangling::new(inner:SetOnDrop(&mut success)));
66 assert!(success);
67}
68