aboutsummaryrefslogtreecommitdiff
path: root/src/condition.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/condition.rs')
-rw-r--r--src/condition.rs156
1 files changed, 156 insertions, 0 deletions
diff --git a/src/condition.rs b/src/condition.rs
new file mode 100644
index 0000000..7a873a8
--- /dev/null
+++ b/src/condition.rs
@@ -0,0 +1,156 @@
+use std::cmp::{max, min};
+
+use chrono::{Datelike, NaiveDate, NaiveDateTime, NaiveTime};
+use serde::{Deserialize, Serialize};
+use Direction::*;
+use Edge::*;
+
+#[derive(Debug, Clone, Serialize, Deserialize)]
+pub enum Condition {
+ From(Box<Condition>),
+
+ Or(Vec<Condition>),
+ And(Vec<Condition>),
+ Invert(Box<Condition>),
+
+ Equal {
+ prop: Property,
+ value: i32,
+ modulus: Option<i32>,
+ },
+ Range {
+ prop: Property,
+ min: i32,
+ max: i32,
+ modulus: Option<i32>,
+ },
+}
+
+#[derive(Debug, Clone, Copy, Serialize, Deserialize)]
+pub enum Property {
+ Year,
+ Monthofyear,
+ Weekofmonth,
+ Dayofyear,
+ Dayofmonth,
+ Dayofweek,
+ Hour,
+ Minute,
+ Second,
+ Unix,
+}
+
+#[derive(Debug, Clone, Serialize, Deserialize)]
+pub struct Range<T>(T, T);
+impl<T: PartialOrd + PartialEq> Range<T> {
+ pub fn includes(&self, a: T) -> bool {
+ a > self.0 && a < self.1
+ }
+}
+
+#[derive(Debug, Clone, Copy)]
+pub enum Edge {
+ Start,
+ End,
+}
+#[derive(Debug, Clone, Copy)]
+pub enum Direction {
+ Forward,
+ Backward,
+}
+
+impl Condition {
+ pub fn find(&self, edge: Edge, dir: Direction, from: NaiveDateTime) -> Option<NaiveDateTime> {
+ match self {
+ Condition::And(_) => todo!(),
+ Condition::Or(cs) => {
+ cs.iter()
+ .filter_map(|c| c.find(edge, dir, from))
+ .reduce(match dir {
+ Forward => min,
+ Backward => max,
+ })
+ }
+ Condition::From(c) => todo!(),
+ Condition::Invert(c) => c.find(edge.invert(), dir, from),
+ Condition::Equal {
+ prop,
+ value,
+ modulus,
+ } => {
+ let geq = match dir {
+ Forward => |a: i32, b: i32| a >= b,
+ Backward => |a: i32, b: i32| a < b,
+ };
+ let off = match edge {
+ Start => 0,
+ End => 1,
+ };
+ match prop {
+ Property::Year => {
+ if geq(from.year(), *value + off) {
+ None
+ } else {
+ Some(NaiveDateTime::new(
+ NaiveDate::from_ymd(*value + off, 1, 1),
+ NaiveTime::from_hms(0, 0, 0),
+ ))
+ }
+ }
+ Property::Monthofyear => todo!(),
+ Property::Weekofmonth => todo!(),
+ Property::Dayofyear => todo!(),
+ Property::Dayofmonth => todo!(),
+ Property::Dayofweek => todo!(),
+ Property::Hour => todo!(),
+ Property::Minute => todo!(),
+ Property::Second => todo!(),
+ Property::Unix => todo!(),
+ }
+ }
+ Condition::Range {
+ prop,
+ min,
+ max,
+ modulus,
+ } => todo!(),
+ }
+ }
+}
+
+impl Edge {
+ pub fn invert(self) -> Self {
+ match self {
+ Edge::Start => Edge::End,
+ Edge::End => Edge::Start,
+ }
+ }
+}
+
+#[cfg(test)]
+mod test {
+ use super::{Condition, Direction, Edge, Property};
+ use chrono::NaiveDateTime;
+ use std::str::FromStr;
+
+ #[test]
+ fn a() {
+ let cond = Condition::Equal {
+ modulus: None,
+ prop: Property::Year,
+ value: 2023,
+ };
+
+ let dt = NaiveDateTime::from_str("2022-06-07T13:37:48").unwrap();
+ assert_eq!(
+ cond.find(Edge::Start, Direction::Forward, dt).unwrap(),
+ NaiveDateTime::from_str("2023-01-01T00:00:00").unwrap(),
+ );
+ assert_eq!(
+ cond.find(Edge::End, Direction::Forward, dt).unwrap(),
+ NaiveDateTime::from_str("2024-01-01T00:00:00").unwrap(),
+ );
+ assert_eq!(cond.find(Edge::End, Direction::Backward, dt), None);
+ assert_eq!(cond.find(Edge::Start, Direction::Backward, dt), None);
+ }
+}