//@ run-pass //@ check-run-results // struct `Foo` has both sync and async drop. // Struct `Complex` contains three `Foo` fields and one of them is moved out. #![feature(async_drop)] #![allow(incomplete_features)] use std::mem::ManuallyDrop; //@ edition: 2021 #[inline(never)] fn myprintln(msg: &str, my_resource_handle: usize) { println!("{} : {}", msg, my_resource_handle); } use std::{ future::{Future, async_drop_in_place, AsyncDrop}, pin::{pin, Pin}, sync::{mpsc, Arc}, task::{Context, Poll, Wake, Waker}, }; struct Foo { my_resource_handle: usize, } #[allow(dead_code)] struct Complex { field1: Foo, field2: Foo, field3: Foo, } impl Complex { fn new(my_resource_handle: usize) -> Self { myprintln("Complex::new()", my_resource_handle); let field1 = Foo::new(my_resource_handle); let field2 = Foo::new(my_resource_handle + 1); let field3 = Foo::new(my_resource_handle + 2); Complex { field1, field2, field3 } } } impl Foo { fn new(my_resource_handle: usize) -> Self { let out = Foo { my_resource_handle, }; myprintln("Foo::new()", my_resource_handle); out } } impl Drop for Foo { fn drop(&mut self) { myprintln("Foo::drop()", self.my_resource_handle); } } impl AsyncDrop for Foo { async fn drop(self: Pin<&mut Self>) { myprintln("Foo::async drop()", self.my_resource_handle); } } fn main() { { let _ = Foo::new(7); } println!("Middle"); // Inside field1 and field3 of Complex must be dropped (as async drop) // field2 must be dropped here (as sync drop) { let _field2 = block_on(bar(10)); } println!("Done") } async fn bar(ident_base: usize) -> Foo { let complex = Complex::new(ident_base); complex.field2 } fn block_on(fut_unpin: F) -> F::Output where F: Future, { let mut fut_pin = pin!(ManuallyDrop::new(fut_unpin)); let mut fut: Pin<&mut F> = unsafe { Pin::map_unchecked_mut(fut_pin.as_mut(), |x| &mut **x) }; let (waker, rx) = simple_waker(); let mut context = Context::from_waker(&waker); let rv = loop { match fut.as_mut().poll(&mut context) { Poll::Ready(out) => break out, // expect wake in polls Poll::Pending => rx.try_recv().unwrap(), } }; let drop_fut_unpin = unsafe { async_drop_in_place(fut.get_unchecked_mut()) }; let mut drop_fut: Pin<&mut _> = pin!(drop_fut_unpin); loop { match drop_fut.as_mut().poll(&mut context) { Poll::Ready(()) => break, Poll::Pending => rx.try_recv().unwrap(), } } rv } fn simple_waker() -> (Waker, mpsc::Receiver<()>) { struct SimpleWaker { tx: std::sync::mpsc::Sender<()>, } impl Wake for SimpleWaker { fn wake(self: Arc) { self.tx.send(()).unwrap(); } } let (tx, rx) = mpsc::channel(); (Waker::from(Arc::new(SimpleWaker { tx })), rx) }