use core::future::Future;
use super::super::execution::async_exec::{AsyncRetryExec, AsyncRetryExecWithStats, NoAsyncSleep};
use super::super::execution::common::AsyncRetryOp;
use super::super::time::ElapsedTracker;
use super::super::{ExecutionHooks, RetryPolicy};
use crate::state::RetryState;
use crate::{predicate, stop, wait};
#[allow(clippy::type_complexity)]
pub trait AsyncRetryExt<T, E, Fut>: FnMut() -> Fut + Sized
where
Fut: Future<Output = Result<T, E>>,
{
fn retry_async(self) -> DefaultAsyncRetryBuilder<Self, Fut, T, E>;
}
#[doc(hidden)]
pub struct StatelessAsyncOp<F>(F);
impl<T, E, Fut: Future<Output = Result<T, E>>, F: FnMut() -> Fut> AsyncRetryOp<T, E, Fut>
for StatelessAsyncOp<F>
{
fn call_op(&mut self, _state: RetryState) -> Fut {
(self.0)()
}
}
impl<T, E, Fut, F> AsyncRetryExt<T, E, Fut> for F
where
F: FnMut() -> Fut + Sized,
Fut: Future<Output = Result<T, E>>,
{
fn retry_async(self) -> DefaultAsyncRetryBuilder<Self, Fut, T, E> {
AsyncRetryExec::new(
RetryPolicy::default(),
ExecutionHooks::new(),
StatelessAsyncOp(self),
NoAsyncSleep,
ElapsedTracker::new(None),
)
}
}
pub type AsyncRetryBuilder<S, W, P, BA, AA, OX, F, Fut, SleepImpl, T, E, SleepFut = ()> =
AsyncRetryExec<RetryPolicy<S, W, P>, BA, AA, OX, F, Fut, SleepImpl, T, E, SleepFut>;
pub type AsyncRetryBuilderWithStats<S, W, P, BA, AA, OX, F, Fut, SleepImpl, T, E, SleepFut = ()> =
AsyncRetryExecWithStats<RetryPolicy<S, W, P>, BA, AA, OX, F, Fut, SleepImpl, T, E, SleepFut>;
pub type DefaultAsyncRetryBuilder<F, Fut, T, E> = AsyncRetryBuilder<
stop::StopAfterAttempts,
wait::WaitExponential,
predicate::PredicateAnyError,
(),
(),
(),
StatelessAsyncOp<F>,
Fut,
NoAsyncSleep,
T,
E,
(),
>;
pub type DefaultAsyncRetryBuilderWithStats<F, Fut, SleepImpl, T, E, SleepFut = ()> =
AsyncRetryBuilderWithStats<
stop::StopAfterAttempts,
wait::WaitExponential,
predicate::PredicateAnyError,
(),
(),
(),
StatelessAsyncOp<F>,
Fut,
SleepImpl,
T,
E,
SleepFut,
>;
#[doc(hidden)]
#[allow(dead_code)]
fn _async_retry_builder_requires_sleep_before_await() {}
impl<S, W, P, F, Fut, T, E>
AsyncRetryExec<RetryPolicy<S, W, P>, (), (), (), F, Fut, NoAsyncSleep, T, E, ()>
where
F: FnMut(RetryState) -> Fut,
{
pub(crate) fn from_policy(policy: RetryPolicy<S, W, P>, op: F) -> Self {
AsyncRetryExec::new(
policy,
ExecutionHooks::new(),
op,
NoAsyncSleep,
ElapsedTracker::new(None),
)
}
}
#[allow(clippy::type_complexity)]
impl<S, W, P, BA, AA, OX, F, Fut, SleepImpl, T, E, SleepFut>
AsyncRetryExec<RetryPolicy<S, W, P>, BA, AA, OX, F, Fut, SleepImpl, T, E, SleepFut>
{
#[must_use]
pub fn stop<NewStop>(
self,
stop: NewStop,
) -> AsyncRetryExec<RetryPolicy<NewStop, W, P>, BA, AA, OX, F, Fut, SleepImpl, T, E, SleepFut>
{
self.map_policy(|policy| policy.stop(stop))
}
#[must_use]
pub fn wait<NewWait>(
self,
wait: NewWait,
) -> AsyncRetryExec<RetryPolicy<S, NewWait, P>, BA, AA, OX, F, Fut, SleepImpl, T, E, SleepFut>
{
self.map_policy(|policy| policy.wait(wait))
}
#[must_use]
pub fn when<NewPredicate>(
self,
predicate: NewPredicate,
) -> AsyncRetryExec<
RetryPolicy<S, W, NewPredicate>,
BA,
AA,
OX,
F,
Fut,
SleepImpl,
T,
E,
SleepFut,
> {
self.map_policy(|policy| policy.when(predicate))
}
#[must_use]
pub fn until<NewPredicate>(
self,
predicate: NewPredicate,
) -> AsyncRetryExec<
RetryPolicy<S, W, predicate::PredicateUntil<NewPredicate>>,
BA,
AA,
OX,
F,
Fut,
SleepImpl,
T,
E,
SleepFut,
> {
self.map_policy(|policy| policy.until(predicate))
}
}