use std::time::Duration;
use std::thread;
use crate::error::Error;
use crate::backoff::Backoff;
pub trait Operation<T, E> {
fn call_op(&mut self) -> Result<T, Error<E>>;
fn retry<B>(&mut self, backoff: &mut B) -> Result<T, Error<E>>
where B: Backoff
{
let nop = |_, _| ();
self.retry_notify(backoff, nop)
}
fn retry_notify<B, N>(&mut self, backoff: &mut B, mut notify: N) -> Result<T, Error<E>>
where N: Notify<E>,
B: Backoff
{
backoff.reset();
loop {
let err = match self.call_op() {
Ok(v) => return Ok(v),
Err(err) => err,
};
let err = match err {
Error::Permanent(err) => return Err(Error::Permanent(err)),
Error::Transient(err) => err,
};
let next = match backoff.next_backoff() {
Some(next) => next,
None => return Err(Error::Transient(err)),
};
notify.notify(err, next);
thread::sleep(next);
}
}
}
impl<T, E, F> Operation<T, E> for F
where F: FnMut() -> Result<T, Error<E>>
{
fn call_op(&mut self) -> Result<T, Error<E>> {
self()
}
}
pub trait Notify<E> {
fn notify(&mut self, err: E, duration: Duration);
}
impl<E, F> Notify<E> for F
where F: Fn(E, Duration)
{
fn notify(&mut self, err: E, duration: Duration) {
self(err, duration)
}
}