1use std::ops::{Deref, DerefMut};
2
3pub type AsyncDropFuture<'a> =
4 std::pin::Pin<Box<dyn Future<Output = Result<(), String>> + Send + 'a>>;
5
6pub trait AsyncDrop {
7 fn async_drop(&mut self) -> AsyncDropFuture<'_> {
8 Box::pin(async { Ok(()) })
9 }
10}
11
12pub struct Dropper<T>
13where
14 T: AsyncDrop + Send + Sync + 'static,
15{
16 inner: Option<T>,
17}
18
19impl<T> Dropper<T>
20where
21 T: AsyncDrop + Send + Sync + 'static,
22{
23 pub fn new(inner: T) -> Self {
24 Self { inner: Some(inner) }
25 }
26}
27
28impl<T> Drop for Dropper<T>
29where
30 T: AsyncDrop + Send + Sync + 'static,
31{
32 fn drop(&mut self) {
33 let Some(mut inner) = self.inner.take() else {
34 return;
35 };
36
37 let (done_trigger, done_signal) = tokio::sync::oneshot::channel();
38
39 tokio::spawn(async move {
40 let result = std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| {
41 futures::executor::block_on(inner.async_drop())
42 }));
43
44 let flattened = match result {
45 Ok(inner) => inner.map_err(|e| format!("Async drop error: {}", e)),
46 Err(_) => Err("Task panicked".to_owned()),
47 };
48
49 let _ = done_trigger.send(flattened);
50 });
51
52 match futures::executor::block_on(done_signal) {
53 Ok(result) => {
54 if let Err(e) = result {
55 eprintln!("{}", e);
56 }
57 }
58 Err(e) => {
59 eprintln!("{}", e);
60 }
61 }
62 }
63}
64
65impl<T> Deref for Dropper<T>
66where
67 T: AsyncDrop + Send + Sync + 'static,
68{
69 type Target = T;
70 fn deref(&self) -> &Self::Target {
71 self.inner
72 .as_ref()
73 .expect("Dropper value has already been dropped")
74 }
75}
76
77impl<T> DerefMut for Dropper<T>
78where
79 T: AsyncDrop + Send + Sync + 'static,
80{
81 fn deref_mut(&mut self) -> &mut Self::Target {
82 self.inner
83 .as_mut()
84 .expect("Dropper value has already been dropped")
85 }
86}