extern crate std;
use std::boxed::Box;
use std::panic;
use core::future::Future;
use core::any::Any;
use core::pin::Pin;
use core::task;
#[must_use]
pub struct CatchUnwindFut<F: panic::UnwindSafe>(pub F);
impl<F: Future + panic::UnwindSafe> Future for CatchUnwindFut<F> {
type Output = Result<F::Output, Box<dyn Any + Send + 'static>>;
#[inline(always)]
fn poll(self: Pin<&mut Self>, ctx: &mut task::Context<'_>) -> task::Poll<Self::Output> {
let fut = unsafe {
self.map_unchecked_mut(|this| &mut this.0)
};
match panic::catch_unwind(panic::AssertUnwindSafe(|| fut.poll(ctx))) {
Ok(task::Poll::Pending) => task::Poll::Pending,
Ok(task::Poll::Ready(res)) => task::Poll::Ready(Ok(res)),
Err(error) => task::Poll::Ready(Err(error)),
}
}
}
pub async fn async_scope<
R,
F: Future<Output = R> + panic::UnwindSafe,
DTORARGS,
DTOR: Future<Output = ()>,
DTORFN: FnOnce(DTORARGS) -> DTOR,
>(
dtor: DTORFN,
args: DTORARGS,
fut: F,
) -> R {
let result = CatchUnwindFut(fut).await;
let dtor = (dtor)(args);
dtor.await;
match result {
Ok(result) => result,
Err(error) => std::panic::resume_unwind(error),
}
}