try-again 0.2.2

Retry synchronous and asynchronous operations.
Documentation
mod retry_async {
    use assertr::assert_that;
    use assertr::prelude::*;
    use std::rc::Rc;
    use std::sync::Arc;
    use std::sync::atomic::{AtomicI32, Ordering};
    use try_again::{IntoStdDuration, delay, retry_async};

    #[tokio::test]
    async fn accepts_function_pointer() {
        async fn test() -> Result<(), ()> {
            Ok(())
        }
        let out = retry_async(test).delayed_by(delay::None.take(0)).await;
        assert_that(out).is_ok().is_equal_to(());
    }

    #[tokio::test]
    async fn accepts_closure() {
        let test = async || -> Result<(), ()> { Ok(()) };
        let out = retry_async(test).delayed_by(delay::None.take(0)).await;
        assert_that(out).is_ok().is_equal_to(());
    }

    #[tokio::test]
    async fn accepts_closure_capturing_owned_value() {
        #[derive(Debug, Clone, PartialEq, Eq)]
        struct Data;

        let data = Data;
        let out: Result<Data, ()> = retry_async(move || {
            let data = data.clone();
            async move { Ok(data) }
        })
        .delayed_by(delay::None.take(0))
        .await;
        assert_that(out).is_ok().is_equal_to(Data);
    }

    #[tokio::test]
    async fn accepts_closure_capturing_reference() {
        #[derive(Debug, Clone, PartialEq, Eq)]
        struct Data;

        async fn foo(_data: &Data) -> Result<(), ()> {
            Ok(())
        }

        let owned = Data;
        let reference = &owned;
        let out: Result<(), ()> = retry_async(|| foo(reference))
            .delayed_by(delay::None.take(0))
            .await;
        assert_that(out).is_ok().is_equal_to(());
    }

    #[tokio::test]
    async fn accepts_closure_capturing_non_send_data() {
        async fn foo(data: Rc<i32>) -> Result<i32, ()> {
            Ok(*data)
        }

        let data = Rc::new(0);
        let out: Result<i32, ()> = retry_async(|| foo(data.clone()))
            .delayed_by(delay::None.take(0))
            .await;
        assert_that(out).is_ok().is_equal_to(0);
    }

    #[tokio::test]
    async fn on_success_never_retries() {
        async fn successful(counter: Arc<AtomicI32>) -> Result<i32, ()> {
            counter.fetch_add(1, Ordering::SeqCst);
            Ok(42)
        }

        let counter = Arc::new(AtomicI32::new(0));

        let out = {
            retry_async(async || successful(counter.clone()).await)
                .delayed_by(delay::Fixed::of(50.millis()).take(3))
                .await
        };

        assert_that(out).is_ok().is_equal_to(42);
        assert_that(counter.load(Ordering::SeqCst))
            .with_detail_message("Function must have been called 1 time only!")
            .is_equal_to(1);
    }

    #[tokio::test]
    async fn on_continuous_error_retries_expected_number_of_times() {
        async fn erroneous(counter: Arc<AtomicI32>) -> Result<(), i32> {
            counter.fetch_add(1, Ordering::SeqCst);
            Err(42)
        }

        let counter = Arc::new(AtomicI32::new(0));

        let out = {
            let counter = counter.clone();
            retry_async(async || erroneous(counter.clone()).await)
                .delayed_by(delay::Fixed::of(50.millis()).take(3))
                .await
        };

        assert_that(out).is_err().is_equal_to(42);
        assert_that(counter.load(Ordering::SeqCst))
            .with_subject_name("Function")
            .is_equal_to(4);
    }
}

mod retry_async_with_options {
    use assertr::assert_that;
    use assertr::prelude::*;
    use std::sync::Arc;
    use std::sync::atomic::{AtomicI32, Ordering};
    use try_again::{
        IntoStdDuration, RetryAsyncOptions, delay, delay_executor::TokioSleep,
        retry_async_with_options,
    };

    #[tokio::test]
    async fn accepts_closure() {
        let test = async || -> Result<(), ()> { Ok(()) };
        let out = retry_async_with_options(
            test,
            RetryAsyncOptions {
                delay_strategy: delay::None.take(0),
                delay_executor: TokioSleep,
                _marker: Default::default(),
            },
        )
        .await;
        assert_that(out).is_ok().is_equal_to(());
    }

    #[tokio::test]
    async fn accepts_function_pointer() {
        async fn test() -> Result<(), ()> {
            Ok(())
        }
        let out = retry_async_with_options(
            test,
            RetryAsyncOptions {
                delay_strategy: delay::None.take(0),
                delay_executor: TokioSleep,
                _marker: Default::default(),
            },
        )
        .await;
        assert_that(out).is_ok().is_equal_to(());
    }

    #[tokio::test]
    async fn on_success_never_retries() {
        async fn successful(counter: Arc<AtomicI32>) -> Result<i32, ()> {
            counter.fetch_add(1, Ordering::SeqCst);
            Ok(42)
        }

        let counter = Arc::new(AtomicI32::new(0));

        let out = {
            retry_async_with_options(
                async || successful(counter.clone()).await,
                RetryAsyncOptions {
                    delay_strategy: delay::Fixed::of(50.millis()).take(3),
                    delay_executor: TokioSleep,
                    _marker: Default::default(),
                },
            )
            .await
        };

        assert_that(out).is_ok().is_equal_to(42);
        assert_that(counter.load(Ordering::SeqCst))
            .with_detail_message("Function must have been called 1 time only!")
            .is_equal_to(1);
    }

    #[tokio::test]
    async fn on_continuous_error_retries_expected_number_of_times() {
        async fn erroneous(counter: Arc<AtomicI32>) -> Result<(), i32> {
            counter.fetch_add(1, Ordering::SeqCst);
            Err(42)
        }

        let counter = Arc::new(AtomicI32::new(0));

        let out = {
            let counter = counter.clone();
            retry_async_with_options(
                async || erroneous(counter.clone()).await,
                RetryAsyncOptions {
                    delay_strategy: delay::Fixed::of(50.millis()).take(3),
                    delay_executor: TokioSleep,
                    _marker: Default::default(),
                },
            )
            .await
        };

        assert_that(out).is_err().is_equal_to(42);
        assert_that(counter.load(Ordering::SeqCst))
            .with_subject_name("Function")
            .is_equal_to(4);
    }
}