use async_trait::async_trait;
use tokio::time::sleep;
use tokio::time::{Duration, Instant};
#[async_trait]
pub trait Waiter<T, E> {
fn default_wait_timeout(&self) -> Option<Duration>;
fn default_delay(&self) -> Duration;
async fn poll(&mut self) -> Result<Option<T>, E>;
fn timeout_error(&self) -> E;
async fn wait(self) -> Result<T, E>
where
Self: Sized,
{
let duration = self.default_wait_timeout();
match duration {
Some(duration) => self.wait_for(duration).await,
None => self.wait_forever().await,
}
}
async fn wait_for(self, duration: Duration) -> Result<T, E>
where
Self: Sized,
{
let delay = self.default_delay();
self.wait_for_with_delay(duration, delay).await
}
async fn wait_for_with_delay(mut self, duration: Duration, delay: Duration) -> Result<T, E>
where
Self: Sized,
{
let start = Instant::now();
while Instant::now().duration_since(start) <= duration {
if let Some(result) = self.poll().await? {
return Ok(result);
};
sleep(delay).await;
}
Err(self.timeout_error())
}
async fn wait_forever(self) -> Result<T, E>
where
Self: Sized,
{
let delay = self.default_delay();
self.wait_forever_with_delay(delay).await
}
async fn wait_forever_with_delay(mut self, delay: Duration) -> Result<T, E>
where
Self: Sized,
{
loop {
if let Some(result) = self.poll().await? {
return Ok(result);
};
sleep(delay).await;
}
}
}
pub trait WaiterCurrentState<T> {
fn waiter_current_state(&self) -> &T;
}