do-over 0.1.0

Async resilience policies for Rust inspired by Polly
Documentation

use tower::Service;
use std::task::{Context, Poll};
use std::sync::Arc;
use tokio::sync::Mutex;
use crate::policy::Policy;

pub struct DoOverService<S, P> {
    inner: Arc<Mutex<S>>,
    policy: P,
}

impl<S, P> DoOverService<S, P> {
    pub fn new(inner: S, policy: P) -> Self {
        Self {
            inner: Arc::new(Mutex::new(inner)),
            policy,
        }
    }
}

impl<S, P, Req, Res, Err> Service<Req> for DoOverService<S, P>
where
    S: Service<Req, Response = Res, Error = Err> + Send + 'static,
    S::Future: Send,
    P: Policy<Err> + Send + Sync + 'static + Clone,
    Req: Send + Sync + Clone + 'static,
    Res: Send + 'static,
    Err: Send + 'static,
{
    type Response = Res;
    type Error = Err;
    type Future = futures::future::BoxFuture<'static, Result<Res, Err>>;

    fn poll_ready(&mut self, _cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
        // Since we're using Arc<Mutex<S>>, we're always ready
        Poll::Ready(Ok(()))
    }

    fn call(&mut self, req: Req) -> Self::Future {
        let inner = Arc::clone(&self.inner);
        let policy = self.policy.clone();
        
        Box::pin(async move {
            policy.execute(|| async {
                let mut svc = inner.lock().await;
                svc.call(req.clone()).await
            }).await
        })
    }
}