core/future/
async_drop.rs

1#![unstable(feature = "async_drop", issue = "126482")]
2
3use crate::fmt;
4use crate::future::{Future, IntoFuture};
5use crate::intrinsics::discriminant_value;
6use crate::marker::{DiscriminantKind, PhantomPinned};
7use crate::mem::MaybeUninit;
8use crate::pin::Pin;
9use crate::task::{Context, Poll, ready};
10
11/// Asynchronously drops a value by running `AsyncDrop::async_drop`
12/// on a value and its fields recursively.
13#[unstable(feature = "async_drop", issue = "126482")]
14pub fn async_drop<T>(value: T) -> AsyncDropOwning<T> {
15    AsyncDropOwning { value: MaybeUninit::new(value), dtor: None, _pinned: PhantomPinned }
16}
17
18/// A future returned by the [`async_drop`].
19#[unstable(feature = "async_drop", issue = "126482")]
20pub struct AsyncDropOwning<T> {
21    value: MaybeUninit<T>,
22    dtor: Option<AsyncDropInPlace<T>>,
23    _pinned: PhantomPinned,
24}
25
26#[unstable(feature = "async_drop", issue = "126482")]
27impl<T> fmt::Debug for AsyncDropOwning<T> {
28    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
29        f.debug_struct("AsyncDropOwning").finish_non_exhaustive()
30    }
31}
32
33#[unstable(feature = "async_drop", issue = "126482")]
34impl<T> Future for AsyncDropOwning<T> {
35    type Output = ();
36
37    fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
38        // SAFETY: Self is pinned thus it is ok to store references to self
39        unsafe {
40            let this = self.get_unchecked_mut();
41            let dtor = Pin::new_unchecked(
42                this.dtor.get_or_insert_with(|| async_drop_in_place(this.value.as_mut_ptr())),
43            );
44            // AsyncDestuctors are idempotent so Self gets idempotency as well
45            dtor.poll(cx)
46        }
47    }
48}
49
50#[lang = "async_drop_in_place"]
51#[allow(unconditional_recursion)]
52// FIXME: Consider if `#[rustc_diagnostic_item = "ptr_drop_in_place"]` is needed?
53unsafe fn async_drop_in_place_raw<T: ?Sized>(
54    to_drop: *mut T,
55) -> <T as AsyncDestruct>::AsyncDestructor {
56    // Code here does not matter - this is replaced by the
57    // real async drop glue constructor by the compiler.
58
59    // SAFETY: see comment above
60    unsafe { async_drop_in_place_raw(to_drop) }
61}
62
63/// Creates the asynchronous destructor of the pointed-to value.
64///
65/// # Safety
66///
67/// Behavior is undefined if any of the following conditions are violated:
68///
69/// * `to_drop` must be [valid](crate::ptr#safety) for both reads and writes.
70///
71/// * `to_drop` must be properly aligned, even if `T` has size 0.
72///
73/// * `to_drop` must be nonnull, even if `T` has size 0.
74///
75/// * The value `to_drop` points to must be valid for async dropping,
76///   which may mean it must uphold additional invariants. These
77///   invariants depend on the type of the value being dropped. For
78///   instance, when dropping a Box, the box's pointer to the heap must
79///   be valid.
80///
81/// * While `async_drop_in_place` is executing or the returned async
82///   destructor is alive, the only way to access parts of `to_drop`
83///   is through the `self: Pin<&mut Self>` references supplied to
84///   the `AsyncDrop::async_drop` methods that `async_drop_in_place`
85///   or `AsyncDropInPlace<T>::poll` invokes. This usually means the
86///   returned future stores the `to_drop` pointer and user is required
87///   to guarantee that dropped value doesn't move.
88///
89#[unstable(feature = "async_drop", issue = "126482")]
90pub unsafe fn async_drop_in_place<T: ?Sized>(to_drop: *mut T) -> AsyncDropInPlace<T> {
91    // SAFETY: `async_drop_in_place_raw` has the same safety requirements
92    unsafe { AsyncDropInPlace(async_drop_in_place_raw(to_drop)) }
93}
94
95/// A future returned by the [`async_drop_in_place`].
96#[unstable(feature = "async_drop", issue = "126482")]
97pub struct AsyncDropInPlace<T: ?Sized>(<T as AsyncDestruct>::AsyncDestructor);
98
99#[unstable(feature = "async_drop", issue = "126482")]
100impl<T: ?Sized> fmt::Debug for AsyncDropInPlace<T> {
101    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
102        f.debug_struct("AsyncDropInPlace").finish_non_exhaustive()
103    }
104}
105
106#[unstable(feature = "async_drop", issue = "126482")]
107impl<T: ?Sized> Future for AsyncDropInPlace<T> {
108    type Output = ();
109
110    #[inline(always)]
111    fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
112        // SAFETY: This code simply forwards poll call to the inner future
113        unsafe { Pin::new_unchecked(&mut self.get_unchecked_mut().0) }.poll(cx)
114    }
115}
116
117// FIXME(zetanumbers): Add same restrictions on AsyncDrop impls as
118//   with Drop impls
119/// Custom code within the asynchronous destructor.
120#[unstable(feature = "async_drop", issue = "126482")]
121#[lang = "async_drop"]
122pub trait AsyncDrop {
123    /// A future returned by the [`AsyncDrop::async_drop`] to be part
124    /// of the async destructor.
125    #[unstable(feature = "async_drop", issue = "126482")]
126    type Dropper<'a>: Future<Output = ()>
127    where
128        Self: 'a;
129
130    /// Constructs the asynchronous destructor for this type.
131    #[unstable(feature = "async_drop", issue = "126482")]
132    fn async_drop(self: Pin<&mut Self>) -> Self::Dropper<'_>;
133}
134
135#[lang = "async_destruct"]
136#[rustc_deny_explicit_impl]
137#[rustc_do_not_implement_via_object]
138trait AsyncDestruct {
139    type AsyncDestructor: Future<Output = ()>;
140}
141
142/// Basically calls `AsyncDrop::async_drop` with pointer. Used to simplify
143/// generation of the code for `async_drop_in_place_raw`
144#[lang = "surface_async_drop_in_place"]
145async unsafe fn surface_async_drop_in_place<T: AsyncDrop + ?Sized>(ptr: *mut T) {
146    // SAFETY: We call this from async drop `async_drop_in_place_raw`
147    //   which has the same safety requirements
148    unsafe { <T as AsyncDrop>::async_drop(Pin::new_unchecked(&mut *ptr)).await }
149}
150
151/// Basically calls `Drop::drop` with pointer. Used to simplify generation
152/// of the code for `async_drop_in_place_raw`
153#[allow(drop_bounds)]
154#[lang = "async_drop_surface_drop_in_place"]
155async unsafe fn surface_drop_in_place<T: Drop + ?Sized>(ptr: *mut T) {
156    // SAFETY: We call this from async drop `async_drop_in_place_raw`
157    //   which has the same safety requirements
158    unsafe { crate::ops::fallback_surface_drop(&mut *ptr) }
159}
160
161/// Wraps a future to continue outputting `Poll::Ready(())` once after
162/// wrapped future completes by returning `Poll::Ready(())` on poll. This
163/// is useful for constructing async destructors to guarantee this
164/// "fuse" property
165//
166// FIXME: Consider optimizing combinators to not have to use fuse in majority
167// of cases, perhaps by adding `#[(rustc_)idempotent(_future)]` attribute for
168// async functions and blocks with the unit return type. However current layout
169// optimizations currently encode `None` case into the async block's discriminant.
170struct Fuse<T> {
171    inner: Option<T>,
172}
173
174#[lang = "async_drop_fuse"]
175fn fuse<T>(inner: T) -> Fuse<T> {
176    Fuse { inner: Some(inner) }
177}
178
179impl<T> Future for Fuse<T>
180where
181    T: Future<Output = ()>,
182{
183    type Output = ();
184
185    fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
186        // SAFETY: pin projection into `self.inner`
187        unsafe {
188            let this = self.get_unchecked_mut();
189            if let Some(inner) = &mut this.inner {
190                ready!(Pin::new_unchecked(inner).poll(cx));
191                this.inner = None;
192            }
193        }
194        Poll::Ready(())
195    }
196}
197
198/// Async destructor for arrays and slices.
199#[lang = "async_drop_slice"]
200async unsafe fn slice<T>(s: *mut [T]) {
201    let len = s.len();
202    let ptr = s.as_mut_ptr();
203    for i in 0..len {
204        // SAFETY: we iterate over elements of `s` slice
205        unsafe { async_drop_in_place_raw(ptr.add(i)).await }
206    }
207}
208
209/// Constructs a chain of two futures, which awaits them sequentially as
210/// a future.
211#[lang = "async_drop_chain"]
212async fn chain<F, G>(first: F, last: G)
213where
214    F: IntoFuture<Output = ()>,
215    G: IntoFuture<Output = ()>,
216{
217    first.await;
218    last.await;
219}
220
221/// Basically a lazy version of `async_drop_in_place`. Returns a future
222/// that would call `AsyncDrop::async_drop` on a first poll.
223///
224/// # Safety
225///
226/// Same as `async_drop_in_place` except is lazy to avoid creating
227/// multiple mutable references.
228#[lang = "async_drop_defer"]
229async unsafe fn defer<T: ?Sized>(to_drop: *mut T) {
230    // SAFETY: same safety requirements as `async_drop_in_place`
231    unsafe { async_drop_in_place(to_drop) }.await
232}
233
234/// If `T`'s discriminant is equal to the stored one then awaits `M`
235/// otherwise awaits the `O`.
236///
237/// # Safety
238///
239/// Users should carefully manage the returned future, since it would
240/// try creating an immutable reference from `this` and get pointee's
241/// discriminant.
242// FIXME(zetanumbers): Send and Sync impls
243#[lang = "async_drop_either"]
244async unsafe fn either<O: IntoFuture<Output = ()>, M: IntoFuture<Output = ()>, T>(
245    other: O,
246    matched: M,
247    this: *mut T,
248    discr: <T as DiscriminantKind>::Discriminant,
249) {
250    // SAFETY: Guaranteed by the safety section of this funtion's documentation
251    if unsafe { discriminant_value(&*this) } == discr {
252        drop(other);
253        matched.await
254    } else {
255        drop(matched);
256        other.await
257    }
258}
259
260#[lang = "async_drop_deferred_drop_in_place"]
261async unsafe fn deferred_drop_in_place<T>(to_drop: *mut T) {
262    // SAFETY: same safety requirements as with drop_in_place (implied by
263    // function's name)
264    unsafe { crate::ptr::drop_in_place(to_drop) }
265}
266
267/// Used for noop async destructors. We don't use [`core::future::Ready`]
268/// because it panics after its second poll, which could be potentially
269/// bad if that would happen during the cleanup.
270#[derive(Clone, Copy)]
271struct Noop;
272
273#[lang = "async_drop_noop"]
274fn noop() -> Noop {
275    Noop
276}
277
278impl Future for Noop {
279    type Output = ();
280
281    fn poll(self: Pin<&mut Self>, _: &mut Context<'_>) -> Poll<Self::Output> {
282        Poll::Ready(())
283    }
284}