mod every;
mod never;
mod once_a_day;
pub use self::{every::Every, never::Never, once_a_day::OnceADayAt};
pub use chrono;
use either::Either;
use std::{convert::Infallible, error::Error, fmt::Display, future::Future, time::Duration};
use crate::maybe_send::{MaybeSend, MaybeSendSync};
pub trait Trigger: MaybeSendSync {
type Err: Into<Box<dyn Error + Send + Sync>>;
fn wait(&mut self) -> impl Future<Output = Result<TriggerResult, Self::Err>> + MaybeSend;
fn twice_as_duration(&self) -> Duration;
}
#[derive(Clone, Copy, Debug)]
pub enum TriggerResult {
Resume,
Stop,
}
impl Trigger for () {
type Err = <Never as Trigger>::Err;
async fn wait(&mut self) -> Result<TriggerResult, Self::Err> {
Never.wait().await
}
fn twice_as_duration(&self) -> Duration {
Never.twice_as_duration()
}
}
impl<T: Trigger> Trigger for Option<T> {
type Err = T::Err;
async fn wait(&mut self) -> Result<TriggerResult, Self::Err> {
match self {
Some(inner) => inner.wait().await,
None => Never.wait().await.map_err(|e| match e {}),
}
}
fn twice_as_duration(&self) -> Duration {
match self {
Some(inner) => inner.twice_as_duration(),
None => Never.twice_as_duration(),
}
}
}
impl<T: Trigger> Trigger for &mut T {
type Err = T::Err;
fn wait(&mut self) -> impl Future<Output = Result<TriggerResult, Self::Err>> + MaybeSend {
(**self).wait()
}
fn twice_as_duration(&self) -> Duration {
(**self).twice_as_duration()
}
}
impl<A, B> Trigger for Either<A, B>
where
A: Trigger,
B: Trigger,
{
type Err = Box<dyn Error + Send + Sync>;
async fn wait(&mut self) -> Result<TriggerResult, Self::Err> {
match self {
Either::Left(tr) => tr.wait().await.map_err(Into::into),
Either::Right(tr) => tr.wait().await.map_err(Into::into),
}
}
fn twice_as_duration(&self) -> Duration {
self.as_ref()
.map_either(Trigger::twice_as_duration, Trigger::twice_as_duration)
.into_inner()
}
}
impl Trigger for Infallible {
type Err = Infallible;
async fn wait(&mut self) -> Result<TriggerResult, Self::Err> {
match *self {}
}
fn twice_as_duration(&self) -> Duration {
match *self {}
}
}
#[cfg(feature = "nightly")]
impl Trigger for ! {
type Err = !;
async fn wait(&mut self) -> Result<TriggerResult, Self::Err> {
match *self {}
}
fn twice_as_duration(&self) -> Duration {
match *self {}
}
}
async fn sleep(duration: Duration) {
const SECS_IN_MIN: u64 = 60;
{
let mins = duration.as_secs() / SECS_IN_MIN;
let remainder = duration.as_secs() % SECS_IN_MIN;
let show_remaining_secs = mins < 5 && remainder > 0;
let display_remainder: (&dyn Display, &'static str) = if show_remaining_secs {
(&remainder, "s")
} else {
(&"", "")
};
tracing::debug!(
"Putting job to sleep for {mins}m{}{}",
display_remainder.0,
display_remainder.1
);
}
tokio::time::sleep(duration).await;
}