Last active
May 5, 2021 06:27
-
-
Save Lucretiel/c60cc8c43ec0f527d7b4b8d55e0bed81 to your computer and use it in GitHub Desktop.
A future adapter that retries the future if it panics
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
use std::{ | |
future::Future, | |
panic::{catch_unwind, UnwindSafe}, | |
pin::Pin, | |
task::{Context, Poll}, | |
}; | |
use pin_project::pin_project; | |
#[pin_project] | |
#[derive(Debug, Clone)] | |
pub struct RetryOnPanic<F> { | |
original: F, | |
#[pin] | |
attempt: F, | |
} | |
pub fn retry_on_panic<F>(fut: F) -> RetryOnPanic<F> | |
where | |
F: Future + Clone, | |
for<'a> &'a mut F: UnwindSafe, | |
{ | |
RetryOnPanic { | |
attempt: fut.clone(), | |
original: fut, | |
} | |
} | |
impl<F: Future + Clone> Future for RetryOnPanic<F> | |
where | |
for<'a> &'a mut F: UnwindSafe, | |
{ | |
type Output = F::Output; | |
fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> { | |
let waker = cx.waker(); | |
let attempt = self.as_mut().project().attempt; | |
match catch_unwind(|| { | |
let mut cx = Context::from_waker(waker); | |
attempt.poll(&mut cx) | |
}) { | |
Ok(polled) => polled, | |
Err(..) => { | |
let retry = self.as_mut().project().original.clone(); | |
self.as_mut().project().attempt.set(retry); | |
waker.wake_by_ref(); | |
Poll::Pending | |
} | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment