• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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()54 fn 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