Skip to main content

async_drop/
lib.rs

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}