use std::{fmt, sync::Arc};
use chrono::{DateTime, TimeZone};
#[derive(Clone)]
pub struct Entry<Z>
where
Z: TimeZone + Sync + Send + 'static,
{
pub id: usize,
pub next: Option<DateTime<Z>>,
pub run: Arc<dyn Fn() + Send + Sync + 'static>,
pub schedule: Option<cron::Schedule>,
}
impl<Z> fmt::Debug for Entry<Z>
where
Z: TimeZone + Sync + Send + 'static,
Z::Offset: fmt::Debug,
{
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("Entry")
.field("id", &self.id)
.field("next", &self.next)
.field("schedule", &self.schedule)
.finish()
}
}
impl<Z> Entry<Z>
where
Z: TimeZone + Sync + Send + 'static,
{
pub fn schedule_next(&self, tz: Z) -> Option<DateTime<Z>> {
self.schedule.as_ref().and_then(|s| s.upcoming(tz).next())
}
pub fn is_once(&self) -> bool {
self.schedule.is_none()
}
}
#[cfg(test)]
mod tests {
use super::*;
use chrono::Utc;
use std::sync::Arc;
#[test]
fn test_entry_debug() {
let entry: Entry<Utc> = Entry {
id: 1,
next: None,
run: Arc::new(|| {}),
schedule: Some("* * * * * *".parse().unwrap()),
};
let debug_str = format!("{:?}", entry);
assert!(debug_str.contains("Entry"));
assert!(debug_str.contains("id: 1"));
}
#[test]
fn test_entry_schedule_next() {
let entry: Entry<Utc> = Entry {
id: 1,
next: None,
run: Arc::new(|| {}),
schedule: Some("* * * * * *".parse().unwrap()),
};
let now = Utc::now();
let next = entry.schedule_next(Utc);
assert!(next.is_some());
assert!(next.unwrap() > now);
}
#[test]
fn test_entry_clone() {
let entry: Entry<Utc> = Entry {
id: 1,
next: None,
run: Arc::new(|| {}),
schedule: Some("* * * * * *".parse().unwrap()),
};
let cloned = entry.clone();
assert_eq!(cloned.id, entry.id);
}
#[test]
fn test_entry_once() {
let entry: Entry<Utc> = Entry {
id: 1,
next: Some(Utc::now()),
run: Arc::new(|| {}),
schedule: None,
};
let next = entry.schedule_next(Utc);
assert!(next.is_none());
}
}