#![unstable(feature = "async_drop", issue = "none")] use crate::fmt; use crate::future::{Future, IntoFuture}; use crate::intrinsics::discriminant_value; use crate::marker::{DiscriminantKind, PhantomPinned}; use crate::mem::MaybeUninit; use crate::pin::Pin; use crate::task::{ready, Context, Poll}; /// Asynchronously drops a value by running `AsyncDrop::async_drop` /// on a value and its fields recursively. #[unstable(feature = "async_drop", issue = "none")] pub fn async_drop(value: T) -> AsyncDropOwning { AsyncDropOwning { value: MaybeUninit::new(value), dtor: None, _pinned: PhantomPinned } } /// A future returned by the [`async_drop`]. #[unstable(feature = "async_drop", issue = "none")] pub struct AsyncDropOwning { value: MaybeUninit, dtor: Option>, _pinned: PhantomPinned, } #[unstable(feature = "async_drop", issue = "none")] impl fmt::Debug for AsyncDropOwning { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_struct("AsyncDropOwning").finish_non_exhaustive() } } #[unstable(feature = "async_drop", issue = "none")] impl Future for AsyncDropOwning { type Output = (); fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { // SAFETY: Self is pinned thus it is ok to store references to self unsafe { let this = self.get_unchecked_mut(); let dtor = Pin::new_unchecked( this.dtor.get_or_insert_with(|| async_drop_in_place(this.value.as_mut_ptr())), ); // AsyncDestuctors are idempotent so Self gets idempotency as well dtor.poll(cx) } } } #[lang = "async_drop_in_place"] #[allow(unconditional_recursion)] // FIXME: Consider if `#[rustc_diagnostic_item = "ptr_drop_in_place"]` is needed? unsafe fn async_drop_in_place_raw( to_drop: *mut T, ) -> ::AsyncDestructor { // Code here does not matter - this is replaced by the // real async drop glue constructor by the compiler. // SAFETY: see comment above unsafe { async_drop_in_place_raw(to_drop) } } /// Creates the asynchronous destructor of the pointed-to value. /// /// # Safety /// /// Behavior is undefined if any of the following conditions are violated: /// /// * `to_drop` must be [valid](crate::ptr#safety) for both reads and writes. /// /// * `to_drop` must be properly aligned, even if `T` has size 0. /// /// * `to_drop` must be nonnull, even if `T` has size 0. /// /// * The value `to_drop` points to must be valid for async dropping, /// which may mean it must uphold additional invariants. These /// invariants depend on the type of the value being dropped. For /// instance, when dropping a Box, the box's pointer to the heap must /// be valid. /// /// * While `async_drop_in_place` is executing or the returned async /// destructor is alive, the only way to access parts of `to_drop` /// is through the `self: Pin<&mut Self>` references supplied to /// the `AsyncDrop::async_drop` methods that `async_drop_in_place` /// or `AsyncDropInPlace::poll` invokes. This usually means the /// returned future stores the `to_drop` pointer and user is required /// to guarantee that dropped value doesn't move. /// #[unstable(feature = "async_drop", issue = "none")] pub unsafe fn async_drop_in_place(to_drop: *mut T) -> AsyncDropInPlace { // SAFETY: `async_drop_in_place_raw` has the same safety requirements unsafe { AsyncDropInPlace(async_drop_in_place_raw(to_drop)) } } /// A future returned by the [`async_drop_in_place`]. #[unstable(feature = "async_drop", issue = "none")] pub struct AsyncDropInPlace(::AsyncDestructor); #[unstable(feature = "async_drop", issue = "none")] impl fmt::Debug for AsyncDropInPlace { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_struct("AsyncDropInPlace").finish_non_exhaustive() } } #[unstable(feature = "async_drop", issue = "none")] impl Future for AsyncDropInPlace { type Output = (); #[inline(always)] fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { // SAFETY: This code simply forwards poll call to the inner future unsafe { Pin::new_unchecked(&mut self.get_unchecked_mut().0) }.poll(cx) } } // FIXME(zetanumbers): Add same restrictions on AsyncDrop impls as // with Drop impls /// Custom code within the asynchronous destructor. #[unstable(feature = "async_drop", issue = "none")] #[lang = "async_drop"] pub trait AsyncDrop { /// A future returned by the [`AsyncDrop::async_drop`] to be part /// of the async destructor. #[unstable(feature = "async_drop", issue = "none")] type Dropper<'a>: Future where Self: 'a; /// Constructs the asynchronous destructor for this type. #[unstable(feature = "async_drop", issue = "none")] fn async_drop(self: Pin<&mut Self>) -> Self::Dropper<'_>; } #[lang = "async_destruct"] #[rustc_deny_explicit_impl(implement_via_object = false)] trait AsyncDestruct { type AsyncDestructor: Future; } /// Basically calls `AsyncDrop::async_drop` with pointer. Used to simplify /// generation of the code for `async_drop_in_place_raw` #[lang = "surface_async_drop_in_place"] async unsafe fn surface_async_drop_in_place(ptr: *mut T) { // SAFETY: We call this from async drop `async_drop_in_place_raw` // which has the same safety requirements unsafe { ::async_drop(Pin::new_unchecked(&mut *ptr)).await } } /// Basically calls `Drop::drop` with pointer. Used to simplify generation /// of the code for `async_drop_in_place_raw` #[allow(drop_bounds)] #[lang = "async_drop_surface_drop_in_place"] async unsafe fn surface_drop_in_place(ptr: *mut T) { // SAFETY: We call this from async drop `async_drop_in_place_raw` // which has the same safety requirements unsafe { crate::ops::fallback_surface_drop(&mut *ptr) } } /// Wraps a future to continue outputing `Poll::Ready(())` once after /// wrapped future completes by returning `Poll::Ready(())` on poll. This /// is useful for constructing async destructors to guarantee this /// "fuse" property // // FIXME: Consider optimizing combinators to not have to use fuse in majority // of cases, perhaps by adding `#[(rustc_)idempotent(_future)]` attribute for // async functions and blocks with the unit return type. However current layout // optimizations currently encode `None` case into the async block's discriminant. struct Fuse { inner: Option, } #[lang = "async_drop_fuse"] fn fuse(inner: T) -> Fuse { Fuse { inner: Some(inner) } } impl Future for Fuse where T: Future, { type Output = (); fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { // SAFETY: pin projection into `self.inner` unsafe { let this = self.get_unchecked_mut(); if let Some(inner) = &mut this.inner { ready!(Pin::new_unchecked(inner).poll(cx)); this.inner = None; } } Poll::Ready(()) } } /// Async destructor for arrays and slices. #[lang = "async_drop_slice"] async unsafe fn slice(s: *mut [T]) { let len = s.len(); let ptr = s.as_mut_ptr(); for i in 0..len { // SAFETY: we iterate over elements of `s` slice unsafe { async_drop_in_place_raw(ptr.add(i)).await } } } /// Construct a chain of two futures, which awaits them sequentially as /// a future. #[lang = "async_drop_chain"] async fn chain(first: F, last: G) where F: IntoFuture, G: IntoFuture, { first.await; last.await; } /// Basically a lazy version of `async_drop_in_place`. Returns a future /// that would call `AsyncDrop::async_drop` on a first poll. /// /// # Safety /// /// Same as `async_drop_in_place` except is lazy to avoid creating /// multiple mutable refernces. #[lang = "async_drop_defer"] async unsafe fn defer(to_drop: *mut T) { // SAFETY: same safety requirements as `async_drop_in_place` unsafe { async_drop_in_place(to_drop) }.await } /// If `T`'s discriminant is equal to the stored one then awaits `M` /// otherwise awaits the `O`. /// /// # Safety /// /// User should carefully manage returned future, since it would /// try creating an immutable referece from `this` and get pointee's /// discriminant. // FIXME(zetanumbers): Send and Sync impls #[lang = "async_drop_either"] async unsafe fn either, M: IntoFuture, T>( other: O, matched: M, this: *mut T, discr: ::Discriminant, ) { // SAFETY: Guaranteed by the safety section of this funtion's documentation if unsafe { discriminant_value(&*this) } == discr { drop(other); matched.await } else { drop(matched); other.await } } #[cfg(not(bootstrap))] #[lang = "async_drop_deferred_drop_in_place"] async unsafe fn deferred_drop_in_place(to_drop: *mut T) { // SAFETY: same safety requirements as with drop_in_place (implied by // function's name) unsafe { crate::ptr::drop_in_place(to_drop) } } /// Used for noop async destructors. We don't use [`core::future::Ready`] /// because it panics after its second poll, which could be potentially /// bad if that would happen during the cleanup. #[derive(Clone, Copy)] struct Noop; #[lang = "async_drop_noop"] fn noop() -> Noop { Noop } impl Future for Noop { type Output = (); fn poll(self: Pin<&mut Self>, _: &mut Context<'_>) -> Poll { Poll::Ready(()) } }