maybe_unwind/futures.rs
1use crate::unwind::{maybe_unwind, Unwind};
2use futures_core::{
3 future::Future,
4 task::{self, Poll},
5};
6use std::{
7 panic::{AssertUnwindSafe, UnwindSafe},
8 pin::Pin,
9};
10
11/// A future for the [`maybe_unwind`] method.
12///
13/// [`maybe_unwind`]: ./trait.FutureMaybeUnwindExt.html#method.maybe_unwind
14#[derive(Debug)]
15#[cfg_attr(docs, doc(cfg(feature = "futures")))]
16#[must_use = "futures do nothing unless you `.await` or poll them"]
17pub struct MaybeUnwind<F> {
18 inner: F,
19}
20
21impl<F> Future for MaybeUnwind<F>
22where
23 F: Future + UnwindSafe,
24{
25 type Output = Result<F::Output, Unwind>;
26
27 fn poll(self: Pin<&mut Self>, cx: &mut task::Context<'_>) -> Poll<Self::Output> {
28 let inner = unsafe { self.map_unchecked_mut(|me| &mut me.inner) };
29 maybe_unwind(AssertUnwindSafe(|| inner.poll(cx)))?.map(Ok)
30 }
31}
32
33/// An extension trait for `Future`s that provides an adaptor for capturing
34/// the unwinding panic information.
35#[cfg_attr(docs, doc(cfg(feature = "futures")))]
36pub trait FutureMaybeUnwindExt: Future + Sized {
37 /// Catches unwinding panics while polling the future.
38 ///
39 /// This is a variant of [`catch_unwind`] that also captures
40 /// the panic information.
41 ///
42 /// # Example
43 ///
44 /// ```
45 /// use maybe_unwind::FutureMaybeUnwindExt as _;
46 ///
47 /// std::panic::set_hook(Box::new(|info| {
48 /// maybe_unwind::capture_panic_info(info);
49 /// }));
50 ///
51 /// # futures_executor::block_on(async {
52 /// let res = do_something_async().maybe_unwind().await;
53 /// # drop(res);
54 /// # });
55 /// # async fn do_something_async() {}
56 /// ```
57 ///
58 /// [`catch_unwind`]: https://docs.rs/futures/0.3/futures/future/trait.FutureExt.html#method.catch_unwind
59 fn maybe_unwind(self) -> MaybeUnwind<Self>
60 where
61 Self: UnwindSafe,
62 {
63 MaybeUnwind { inner: self }
64 }
65}
66
67impl<F: Future> FutureMaybeUnwindExt for F {}