use super::RetryBody;
use crate::Request;
pub trait Policy<R, E>: Send + Sync + 'static {
fn retry(
&self,
req: Request<RetryBody>,
result: Result<R, E>,
) -> impl Future<Output = PolicyResult<R, E>> + Send + '_;
fn clone_input(&self, req: &Request<RetryBody>) -> Option<Request<RetryBody>>;
}
impl<P, R, E> Policy<R, E> for &'static P
where
P: Policy<R, E>,
{
#[inline(always)]
fn retry(
&self,
req: Request<RetryBody>,
result: Result<R, E>,
) -> impl Future<Output = PolicyResult<R, E>> + Send + '_ {
(**self).retry(req, result)
}
#[inline(always)]
fn clone_input(&self, req: &Request<RetryBody>) -> Option<Request<RetryBody>> {
(**self).clone_input(req)
}
}
impl<P, R, E> Policy<R, E> for std::sync::Arc<P>
where
P: Policy<R, E>,
{
#[inline(always)]
fn retry(
&self,
req: Request<RetryBody>,
result: Result<R, E>,
) -> impl Future<Output = PolicyResult<R, E>> + Send + '_ {
(**self).retry(req, result)
}
#[inline(always)]
fn clone_input(&self, req: &Request<RetryBody>) -> Option<Request<RetryBody>> {
(**self).clone_input(req)
}
}
#[expect(
clippy::large_enum_variant,
reason = "retry hands the request back without adding an allocation"
)]
pub enum PolicyResult<R, E> {
Abort(Result<R, E>),
Retry {
req: Request<RetryBody>,
},
}
impl<R, E> std::fmt::Debug for PolicyResult<R, E>
where
R: std::fmt::Debug,
E: std::fmt::Debug,
{
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Self::Abort(err) => write!(f, "PolicyResult::Abort({err:?})"),
Self::Retry { req } => {
write!(f, "PolicyResult::Retry {{ req: {req:?} }}",)
}
}
}
}
macro_rules! impl_retry_policy_either {
($id:ident, $($param:ident),+ $(,)?) => {
impl<$($param),+, Response, Error> Policy< Response, Error> for rama_core::combinators::$id<$($param),+>
where
$($param: Policy< Response, Error>),+,
Response: Send + 'static,
Error: Send + 'static,
{
async fn retry(
&self,
req: rama_http_types::Request<RetryBody>,
result: Result<Response, Error>,
) -> PolicyResult< Response, Error> {
match self {
$(
rama_core::combinators::$id::$param(policy) => policy.retry(req, result).await,
)+
}
}
fn clone_input(
&self,
req: &rama_http_types::Request<RetryBody>,
) -> Option<rama_http_types::Request<RetryBody>> {
match self {
$(
rama_core::combinators::$id::$param(policy) => policy.clone_input(req),
)+
}
}
}
};
}
rama_core::combinators::impl_either!(impl_retry_policy_either);