rust/tests/ui/async-await/async-drop/async-drop-open.rs

128 lines
3.0 KiB
Rust

//@ 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<F>(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>) {
self.tx.send(()).unwrap();
}
}
let (tx, rx) = mpsc::channel();
(Waker::from(Arc::new(SimpleWaker { tx })), rx)
}