|
| 1 | +#![unstable(feature = "async_drop", issue = "none")] |
| 2 | + |
| 3 | +use crate::fmt; |
| 4 | +use crate::future::{Future, IntoFuture}; |
| 5 | +use crate::intrinsics::discriminant_value; |
| 6 | +use crate::marker::{DiscriminantKind, PhantomPinned}; |
| 7 | +use crate::mem::MaybeUninit; |
| 8 | +use crate::pin::Pin; |
| 9 | +use crate::task::{ready, Context, Poll}; |
| 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 = "none")] |
| 14 | +pub 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 = "none")] |
| 20 | +pub struct AsyncDropOwning<T> { |
| 21 | + value: MaybeUninit<T>, |
| 22 | + dtor: Option<AsyncDropInPlace<T>>, |
| 23 | + _pinned: PhantomPinned, |
| 24 | +} |
| 25 | + |
| 26 | +#[unstable(feature = "async_drop", issue = "none")] |
| 27 | +impl<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 = "none")] |
| 34 | +impl<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? |
| 53 | +unsafe 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 = "none")] |
| 90 | +pub 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 = "none")] |
| 97 | +pub struct AsyncDropInPlace<T: ?Sized>(<T as AsyncDestruct>::AsyncDestructor); |
| 98 | + |
| 99 | +#[unstable(feature = "async_drop", issue = "none")] |
| 100 | +impl<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 = "none")] |
| 107 | +impl<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 = "none")] |
| 121 | +#[lang = "async_drop"] |
| 122 | +pub 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 = "none")] |
| 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 = "none")] |
| 132 | + fn async_drop(self: Pin<&mut Self>) -> Self::Dropper<'_>; |
| 133 | +} |
| 134 | + |
| 135 | +#[lang = "async_destruct"] |
| 136 | +#[rustc_deny_explicit_impl(implement_via_object = false)] |
| 137 | +trait AsyncDestruct { |
| 138 | + type AsyncDestructor: Future<Output = ()>; |
| 139 | +} |
| 140 | + |
| 141 | +/// Basically calls `AsyncDrop::async_drop` with pointer. Used to simplify |
| 142 | +/// generation of the code for `async_drop_in_place_raw` |
| 143 | +#[lang = "surface_async_drop_in_place"] |
| 144 | +async unsafe fn surface_async_drop_in_place<T: AsyncDrop + ?Sized>(ptr: *mut T) { |
| 145 | + // SAFETY: We call this from async drop `async_drop_in_place_raw` |
| 146 | + // which has the same safety requirements |
| 147 | + unsafe { <T as AsyncDrop>::async_drop(Pin::new_unchecked(&mut *ptr)).await } |
| 148 | +} |
| 149 | + |
| 150 | +/// Basically calls `Drop::drop` with pointer. Used to simplify generation |
| 151 | +/// of the code for `async_drop_in_place_raw` |
| 152 | +#[allow(drop_bounds)] |
| 153 | +#[lang = "async_drop_surface_drop_in_place"] |
| 154 | +async unsafe fn surface_drop_in_place<T: Drop + ?Sized>(ptr: *mut T) { |
| 155 | + // SAFETY: We call this from async drop `async_drop_in_place_raw` |
| 156 | + // which has the same safety requirements |
| 157 | + unsafe { crate::ops::fallback_surface_drop(&mut *ptr) } |
| 158 | +} |
| 159 | + |
| 160 | +/// Wraps a future to continue outputing `Poll::Ready(())` once after |
| 161 | +/// wrapped future completes by returning `Poll::Ready(())` on poll. This |
| 162 | +/// is useful for constructing async destructors to guarantee this |
| 163 | +/// "fuse" property |
| 164 | +struct Fuse<T> { |
| 165 | + inner: Option<T>, |
| 166 | +} |
| 167 | + |
| 168 | +#[lang = "async_drop_fuse"] |
| 169 | +fn fuse<T>(inner: T) -> Fuse<T> { |
| 170 | + Fuse { inner: Some(inner) } |
| 171 | +} |
| 172 | + |
| 173 | +impl<T> Future for Fuse<T> |
| 174 | +where |
| 175 | + T: Future<Output = ()>, |
| 176 | +{ |
| 177 | + type Output = (); |
| 178 | + |
| 179 | + fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> { |
| 180 | + // SAFETY: pin projection into `self.inner` |
| 181 | + unsafe { |
| 182 | + let this = self.get_unchecked_mut(); |
| 183 | + if let Some(inner) = &mut this.inner { |
| 184 | + ready!(Pin::new_unchecked(inner).poll(cx)); |
| 185 | + this.inner = None; |
| 186 | + } |
| 187 | + } |
| 188 | + Poll::Ready(()) |
| 189 | + } |
| 190 | +} |
| 191 | + |
| 192 | +/// Async destructor for arrays and slices. |
| 193 | +#[lang = "async_drop_slice"] |
| 194 | +async unsafe fn slice<T>(s: *mut [T]) { |
| 195 | + let len = s.len(); |
| 196 | + let ptr = s.as_mut_ptr(); |
| 197 | + for i in 0..len { |
| 198 | + // SAFETY: we iterate over elements of `s` slice |
| 199 | + unsafe { async_drop_in_place_raw(ptr.add(i)).await } |
| 200 | + } |
| 201 | +} |
| 202 | + |
| 203 | +/// Construct a chain of two futures, which awaits them sequentially as |
| 204 | +/// a future. |
| 205 | +#[lang = "async_drop_chain"] |
| 206 | +async fn chain<F, G>(first: F, last: G) |
| 207 | +where |
| 208 | + F: IntoFuture<Output = ()>, |
| 209 | + G: IntoFuture<Output = ()>, |
| 210 | +{ |
| 211 | + first.await; |
| 212 | + last.await; |
| 213 | +} |
| 214 | + |
| 215 | +/// Basically a lazy version of `async_drop_in_place`. Returns a future |
| 216 | +/// that would call `AsyncDrop::async_drop` on a first poll. |
| 217 | +/// |
| 218 | +/// # Safety |
| 219 | +/// |
| 220 | +/// Same as `async_drop_in_place` except is lazy to avoid creating |
| 221 | +/// multiple mutable refernces. |
| 222 | +#[lang = "async_drop_defer"] |
| 223 | +async unsafe fn defer<T: ?Sized>(to_drop: *mut T) { |
| 224 | + // SAFETY: same safety requirements as `async_drop_in_place` |
| 225 | + unsafe { async_drop_in_place(to_drop) }.await |
| 226 | +} |
| 227 | + |
| 228 | +/// If `T`'s discriminant is equal to the stored one then awaits `M` |
| 229 | +/// otherwise awaits the `O`. |
| 230 | +/// |
| 231 | +/// # Safety |
| 232 | +/// |
| 233 | +/// User should carefully manage returned future, since it would |
| 234 | +/// try creating an immutable referece from `this` and get pointee's |
| 235 | +/// discriminant. |
| 236 | +// FIXME(zetanumbers): Send and Sync impls |
| 237 | +#[lang = "async_drop_either"] |
| 238 | +async unsafe fn either<O: IntoFuture<Output = ()>, M: IntoFuture<Output = ()>, T>( |
| 239 | + other: O, |
| 240 | + matched: M, |
| 241 | + this: *mut T, |
| 242 | + discr: <T as DiscriminantKind>::Discriminant, |
| 243 | +) { |
| 244 | + // SAFETY: Guaranteed by the safety section of this funtion's documentation |
| 245 | + if unsafe { discriminant_value(&*this) } == discr { |
| 246 | + drop(other); |
| 247 | + matched.await |
| 248 | + } else { |
| 249 | + drop(matched); |
| 250 | + other.await |
| 251 | + } |
| 252 | +} |
| 253 | + |
| 254 | +/// Used for noop async destructors. We don't use [`core::future::Ready`] |
| 255 | +/// because it panics after its second poll, which could be potentially |
| 256 | +/// bad if that would happen during the cleanup. |
| 257 | +#[derive(Clone, Copy)] |
| 258 | +struct Noop; |
| 259 | + |
| 260 | +#[lang = "async_drop_noop"] |
| 261 | +fn noop() -> Noop { |
| 262 | + Noop |
| 263 | +} |
| 264 | + |
| 265 | +impl Future for Noop { |
| 266 | + type Output = (); |
| 267 | + |
| 268 | + fn poll(self: Pin<&mut Self>, _: &mut Context<'_>) -> Poll<Self::Output> { |
| 269 | + Poll::Ready(()) |
| 270 | + } |
| 271 | +} |
0 commit comments