use std::time::Duration;
use tokio_util::sync::CancellationToken;
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum Directive<P = ()> {
Proceed(P),
Idle(P),
Sleep(Duration, P),
}
impl<P> Directive<P> {
pub fn payload(&self) -> &P {
match self {
Self::Proceed(p) | Self::Idle(p) | Self::Sleep(_, p) => p,
}
}
pub fn map<Q>(self, f: impl FnOnce(P) -> Q) -> Directive<Q> {
match self {
Self::Proceed(p) => Directive::Proceed(f(p)),
Self::Idle(p) => Directive::Idle(f(p)),
Self::Sleep(d, p) => Directive::Sleep(d, f(p)),
}
}
pub fn strip(&self) -> Directive<()> {
match self {
Self::Proceed(_) => Directive::Proceed(()),
Self::Idle(_) => Directive::Idle(()),
Self::Sleep(d, _) => Directive::Sleep(*d, ()),
}
}
}
impl Directive<()> {
#[must_use]
pub fn proceed() -> Self {
Self::Proceed(())
}
#[must_use]
pub fn idle() -> Self {
Self::Idle(())
}
#[must_use]
pub fn sleep(d: Duration) -> Self {
Self::Sleep(d, ())
}
}
impl Copy for Directive<()> {}
pub trait WorkerAction: Send {
type Payload: Send + Sync + 'static;
type Error: std::fmt::Display + Send;
fn execute(
&mut self,
cancel: &CancellationToken,
) -> impl std::future::Future<Output = Result<Directive<Self::Payload>, Self::Error>> + Send;
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn directive_convenience_constructors() {
assert_eq!(Directive::proceed(), Directive::Proceed(()));
assert_eq!(Directive::idle(), Directive::Idle(()));
assert_eq!(
Directive::sleep(Duration::from_secs(1)),
Directive::Sleep(Duration::from_secs(1), ()),
);
}
#[test]
fn directive_strip() {
let d = Directive::Proceed(42);
assert_eq!(d.strip(), Directive::proceed());
let d = Directive::Idle("hello");
assert_eq!(d.strip(), Directive::idle());
let d = Directive::Sleep(Duration::from_secs(5), vec![1, 2]);
assert_eq!(d.strip(), Directive::sleep(Duration::from_secs(5)));
}
#[test]
fn directive_payload() {
let d = Directive::Proceed(42);
assert_eq!(*d.payload(), 42);
let d = Directive::Idle("hi");
assert_eq!(*d.payload(), "hi");
}
#[test]
fn directive_map() {
let d = Directive::Proceed(42);
let mapped = d.map(|n| n.to_string());
assert_eq!(mapped, Directive::Proceed("42".to_owned()));
}
#[test]
fn directive_unit_is_copy() {
let d = Directive::idle();
let d2 = d;
assert_eq!(d, d2);
}
#[test]
fn directive_variants_are_distinct() {
assert_ne!(Directive::proceed(), Directive::idle());
assert_ne!(Directive::proceed(), Directive::sleep(Duration::ZERO));
assert_ne!(Directive::idle(), Directive::sleep(Duration::from_secs(1)));
}
#[test]
fn directive_sleep_equality() {
let d = Duration::from_millis(500);
assert_eq!(Directive::sleep(d), Directive::sleep(d));
}
}