diff --git a/Cargo.lock b/Cargo.lock index 9e6625a..06eb7af 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -97,6 +97,15 @@ version = "0.8.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "06ea2b9bc92be3c2baa9334a323ebca2d6f074ff852cd1d7b11064035cd3868f" +[[package]] +name = "croner" +version = "2.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "516aad5374ea0ea75a0f0f4512fb4e7ad46c5eeff9971cb8ebc8fd74f1cd16c1" +dependencies = [ + "chrono", +] + [[package]] name = "eyre" version = "0.6.12" @@ -169,6 +178,7 @@ version = "0.0.5" dependencies = [ "bitflags", "chrono", + "croner", "eyre", "log", "num-traits", diff --git a/Cargo.toml b/Cargo.toml index 4fc3d41..1d84e94 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -30,8 +30,8 @@ path = "lib/lib.rs" # scheduling "sched" = ["dep:chrono", "dep:log"] "sched.tokio" = ["dep:tokio", "tokio?/time", "tokio?/rt", "sched"] -"sched.rule-recurrence" = ["sched"] -"sched.rule-cron" = ["sched"] +"sched.rule-recurrence" = ["sched", "dep:num-traits"] +"sched.rule-cron" = ["sched", "dep:croner"] # utils "utils" = [] "utils.threads" = ["macros", "utils", "dep:log"] @@ -46,6 +46,8 @@ bitflags = { version = "2.5.0", optional = true } chrono = { version = "0.4.37", optional = true } log = { version = "0.4.21", optional = true } tokio = { version = "1.37.0", optional = true } -num-traits = "0.2.18" +croner = { version = "2.0.4", optional = true } +num-traits = { version = "0.2.18", optional = true } + diff --git a/lib/sched/rules.rs b/lib/sched/rules.rs index 77edb7b..7a38039 100644 --- a/lib/sched/rules.rs +++ b/lib/sched/rules.rs @@ -1,11 +1,18 @@ -#[cfg(feature = "sched.rule-cron")] -mod cron; #[cfg(feature = "sched.rule-recurrence")] mod recurrent; #[cfg(feature = "sched.rule-recurrence")] pub use self::recurrent::{many, range, ranges, ruleset, val, RecurrenceRuleSet, Rule}; -use chrono::{DateTime, Local}; +#[cfg(feature = "sched.rule-cron")] +mod cron; +#[cfg(feature = "sched.rule-cron")] +pub use self::cron::Cron; + +use { + chrono::{DateTime, Local}, + eyre::Result, + std::fmt::Debug, +}; /// 🧉 » a scheduling rule /// @@ -24,7 +31,7 @@ pub enum SchedulingRule { /// 🧉 » a scheduling rule expressed in cron format #[cfg(feature = "sched.rule-cron")] - Cron(String), + Cron(Cron), } impl SchedulingRule { @@ -48,9 +55,9 @@ impl SchedulingRule { SchedulingRule::Repeat(rule) => rule.next_match_from(base), #[cfg(feature = "sched.rule-cron")] - SchedulingRule::Cron(_cron) => { - // TODO: implement cron scheduling rule - unimplemented!() + SchedulingRule::Cron(pattern) => { + let next = pattern.find_next_occurrence(&base, false); + next.ok() } } } @@ -58,8 +65,9 @@ impl SchedulingRule { /// 🧉 » create a new `SchedulingRule` that runs at specific intervals defined by a cron expression #[cfg(feature = "sched.rule-cron")] -pub fn cron(cron: &str) -> SchedulingRule { - SchedulingRule::Cron(cron.to_string()) +pub fn cron(pattern: &str) -> Result { + let cron = Cron::new(pattern)?; + Ok(SchedulingRule::Cron(cron)) } /// 🧉 » create a new `SchedulingRule` that runs at specific intervals defined by a `RecurrenceRule` diff --git a/lib/sched/rules/cron.rs b/lib/sched/rules/cron.rs index 100dcbb..639bcb8 100644 --- a/lib/sched/rules/cron.rs +++ b/lib/sched/rules/cron.rs @@ -1 +1,40 @@ -// TODO: cron based scheduling +use { + core::fmt, + croner::Cron as Croner, + eyre::Result, + std::{ + fmt::Debug, + ops::{Deref, DerefMut}, + }, +}; + +#[derive(Clone)] +pub struct Cron(Croner); + +impl Cron { + /// 🧉 » create a new `Cron` scheduling rule + pub fn new(pattern: &str) -> Result { + let cron = Croner::new(pattern).parse()?; + Ok(Self(cron)) + } +} + +impl Debug for Cron { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("Cron").field("expression", &self.0.pattern).finish() + } +} + +impl Deref for Cron { + type Target = Croner; + + fn deref(&self) -> &Self::Target { + &self.0 + } +} + +impl DerefMut for Cron { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.0 + } +}