|
1 | 1 | #![unstable(feature = "async_drop", issue = "126482")]
|
2 | 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::{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")] |
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 = "126482")] |
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 = "126482")] |
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 = "126482")] |
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 |
| -} |
| 3 | +#[allow(unused_imports)] |
| 4 | +use core::future::Future; |
49 | 5 |
|
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 |
| -} |
| 6 | +#[allow(unused_imports)] |
| 7 | +use crate::pin::Pin; |
| 8 | +#[allow(unused_imports)] |
| 9 | +use crate::task::{Context, Poll}; |
62 | 10 |
|
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. |
| 11 | +/// Async version of Drop trait. |
72 | 12 | ///
|
73 |
| -/// * `to_drop` must be nonnull, even if `T` has size 0. |
| 13 | +/// When a value is no longer needed, Rust will run a "destructor" on that value. |
| 14 | +/// The most common way that a value is no longer needed is when it goes out of |
| 15 | +/// scope. Destructors may still run in other circumstances, but we're going to |
| 16 | +/// focus on scope for the examples here. To learn about some of those other cases, |
| 17 | +/// please see [the reference] section on destructors. |
74 | 18 | ///
|
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. |
| 19 | +/// [the reference]: https://doc.rust-lang.org/reference/destructors.html |
80 | 20 | ///
|
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. |
| 21 | +/// ## `Copy` and ([`Drop`]|`AsyncDrop`) are exclusive |
88 | 22 | ///
|
89 |
| -#[unstable(feature = "async_drop", issue = "126482")] |
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 = "126482")] |
97 |
| -pub struct AsyncDropInPlace<T: ?Sized>(<T as AsyncDestruct>::AsyncDestructor); |
98 |
| - |
99 |
| -#[unstable(feature = "async_drop", issue = "126482")] |
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 = "126482")] |
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. |
| 23 | +/// You cannot implement both [`Copy`] and ([`Drop`]|`AsyncDrop`) on the same type. Types that |
| 24 | +/// are `Copy` get implicitly duplicated by the compiler, making it very |
| 25 | +/// hard to predict when, and how often destructors will be executed. As such, |
| 26 | +/// these types cannot have destructors. |
| 27 | +#[cfg(not(bootstrap))] |
120 | 28 | #[unstable(feature = "async_drop", issue = "126482")]
|
121 | 29 | #[lang = "async_drop"]
|
122 | 30 | 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 = "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] |
138 |
| -trait 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"] |
145 |
| -async 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"] |
155 |
| -async 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. |
170 |
| -struct Fuse<T> { |
171 |
| - inner: Option<T>, |
172 |
| -} |
173 |
| - |
174 |
| -#[lang = "async_drop_fuse"] |
175 |
| -fn fuse<T>(inner: T) -> Fuse<T> { |
176 |
| - Fuse { inner: Some(inner) } |
177 |
| -} |
178 |
| - |
179 |
| -impl<T> Future for Fuse<T> |
180 |
| -where |
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"] |
200 |
| -async 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"] |
212 |
| -async fn chain<F, G>(first: F, last: G) |
213 |
| -where |
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"] |
229 |
| -async 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"] |
244 |
| -async 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"] |
261 |
| -async 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)] |
271 |
| -struct Noop; |
272 |
| - |
273 |
| -#[lang = "async_drop_noop"] |
274 |
| -fn noop() -> Noop { |
275 |
| - Noop |
276 |
| -} |
277 |
| - |
278 |
| -impl Future for Noop { |
279 |
| - type Output = (); |
280 |
| - |
281 |
| - fn poll(self: Pin<&mut Self>, _: &mut Context<'_>) -> Poll<Self::Output> { |
282 |
| - Poll::Ready(()) |
283 |
| - } |
| 31 | + /// Executes the async destructor for this type. |
| 32 | + /// |
| 33 | + /// This method is called implicitly when the value goes out of scope, |
| 34 | + /// and cannot be called explicitly. |
| 35 | + /// |
| 36 | + /// When this method has been called, `self` has not yet been deallocated. |
| 37 | + /// That only happens after the method is over. |
| 38 | + /// |
| 39 | + /// # Panics |
| 40 | + #[allow(async_fn_in_trait)] |
| 41 | + async fn drop(self: Pin<&mut Self>); |
| 42 | +} |
| 43 | + |
| 44 | +/// Async drop. |
| 45 | +#[cfg(not(bootstrap))] |
| 46 | +#[unstable(feature = "async_drop", issue = "126482")] |
| 47 | +#[lang = "async_drop_in_place"] |
| 48 | +pub async unsafe fn async_drop_in_place<T: ?Sized>(_to_drop: *mut T) { |
| 49 | + // Code here does not matter - this is replaced by the |
| 50 | + // real implementation by the compiler. |
284 | 51 | }
|
0 commit comments