#[derive(Clone, Debug, PartialEq, Eq, Hash)]
pub enum Delayed<T> {
Pending(std::time::Instant, std::time::Duration, std::time::Duration),
Done(T),
}
pub trait DelayedReadyResolver<D> {
fn handle(&self, item: Delayed<D>);
}
pub type BoxedDelayedReadyResolver<D> = Box<dyn DelayedReadyResolver<D>>;
pub trait DelayedIterator {
type Item;
fn next(&mut self) -> Option<Delayed<Self::Item>>;
fn into_iter(self) -> impl Iterator<Item = Delayed<Self::Item>>
where
Self: Sized + 'static,
{
DelayedAsIterator(Box::new(self))
}
}
pub type BoxedDelayedIterator<D> = Box<dyn Iterator<Item = Delayed<D>>>;
pub struct DelayedAsIterator<T>(Box<dyn DelayedIterator<Item = T>>);
impl<T> DelayedAsIterator<T> {
pub fn from_impl(t: impl DelayedIterator<Item = T> + 'static) -> Self {
Self(Box::new(t))
}
#[must_use]
pub fn new(t: Box<dyn DelayedIterator<Item = T>>) -> Self {
Self(t)
}
}
impl<T> Iterator for DelayedAsIterator<T> {
type Item = Delayed<T>;
fn next(&mut self) -> Option<Self::Item> {
self.0.next()
}
}
#[derive(Clone, Debug)]
pub struct SleepIterator<T>(std::time::Instant, std::time::Duration, Option<T>);
impl<T> SleepIterator<T> {
pub fn new(from: std::time::Instant, until: std::time::Duration, value: T) -> Self {
Self(from, until, Some(value))
}
pub fn until(duration: std::time::Duration, value: T) -> Self {
let from = std::time::Instant::now();
Self(from, duration, Some(value))
}
}
impl<T> DelayedIterator for SleepIterator<T> {
type Item = T;
fn next(&mut self) -> Option<Delayed<Self::Item>> {
self.2.as_ref()?;
let now = std::time::Instant::now();
let result = match self.0.checked_add(self.1) {
Some(completed_at) => match completed_at.checked_duration_since(now) {
Some(diff) => Delayed::Pending(self.0, self.1, diff),
_ => Delayed::Done(self.2.take().expect("item should not be taken yet")),
},
_ => Delayed::Done(self.2.take().expect("item should not be taken yet")),
};
Some(result)
}
}
#[cfg(test)]
mod test_sleep_iterator {
use super::*;
use std::{
thread,
time::{Duration, Instant},
};
use super::SleepIterator;
#[test]
fn zero_duration_sleep_iterator_finishes_immediately() {
let now = Instant::now();
let wait = Duration::from_secs(0);
let mut sleeper = SleepIterator::new(now, wait, ());
assert_eq!(sleeper.next(), Some(Delayed::Done(())));
}
#[test]
fn can_sleep_thread_and_get_final() {
let now = Instant::now();
let wait = Duration::from_secs(3);
let mut sleeper = SleepIterator::new(now, wait, ());
assert!(matches!(sleeper.next(), Some(Delayed::Pending(_, _, _))));
assert!(matches!(sleeper.next(), Some(Delayed::Pending(_, _, _))));
assert!(matches!(sleeper.next(), Some(Delayed::Pending(_, _, _))));
thread::sleep(Duration::from_secs(1));
assert!(matches!(sleeper.next(), Some(Delayed::Pending(_, _, _))));
thread::sleep(Duration::from_secs(2));
assert_eq!(sleeper.next(), Some(Delayed::Done(())));
}
}