aboutsummaryrefslogtreecommitdiff
path: root/karld/src/helper.rs
blob: 2e601b00c4e9c1ddf9ad70f41eef65e96dbb13f5 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
use crate::condition::{ConditionFind, Direction, Edge};
use chrono::{NaiveDate, NaiveDateTime};
use karlcommon::{Schedule, Task};
use std::{collections::HashMap, ops::Range};

pub struct DiscreteCache {
    tasks: HashMap<u64, DiscreteCacheTask>,
}
pub struct DiscreteCacheTask {
    inner: Task,
    cached: Option<Range<NaiveDateTime>>,
    cache: Vec<Range<NaiveDateTime>>,
}

impl DiscreteCache {
    pub fn new_for(tasks: HashMap<u64, Task>) -> Self {
        Self {
            tasks: HashMap::from_iter(
                tasks
                    .into_iter()
                    .map(|(k, v)| (k, DiscreteCacheTask::new(v))),
            ),
        }
    }
}

impl DiscreteCacheTask {
    pub fn new(inner: Task) -> Self {
        Self {
            inner,
            cached: None,
            cache: vec![],
        }
    }

    pub fn find(&mut self, from: NaiveDateTime, dir: Direction) -> Range<Option<NaiveDateTime>> {
        assert_eq!(dir, Direction::Forward);
        // TODO cache
        // if let Some(c) = self.cached {}
        match &self.inner.schedule {
            Schedule::Condition(o) => {
                let start = o.find(Edge::Start, dir, from);
                let end = o.find(Edge::End, dir, from);
                match (start, end) {
                    (Some(start), Some(end)) => {
                        if end < start {
                            if let Some(start) = o.find(Edge::Start, dir.invert(), from) {
                                assert!(start < end);
                                Some(start)..Some(end)
                            } else {
                                None..Some(end)
                            }
                        } else {
                            Some(start)..Some(end)
                        }
                    }
                    (None, Some(end)) => {
                        if let Some(start) = o.find(Edge::Start, dir.invert(), from) {
                            assert!(start < end);
                            Some(start)..Some(end)
                        } else {
                            None..Some(end)
                        }
                    }
                    (Some(start), None) => Some(start)..None,
                    (None, None) => None..None,
                }
            }
            Schedule::Never => None..None,
            Schedule::Static(_) => None..None,      // TODO
            Schedule::Dynamic { .. } => None..None, // TODO
        }
    }
}

pub trait Overlaps<T> {
    fn overlaps(&self, v: T) -> bool;
}
impl Overlaps<i64> for Range<i64> {
    fn overlaps(&self, v: i64) -> bool {
        self.start <= v && v < self.end
    }
}
impl Overlaps<i64> for Range<Option<i64>> {
    fn overlaps(&self, v: i64) -> bool {
        match (self.start, self.end) {
            (Some(s), Some(e)) => s <= v && v < e,
            (Some(s), None) => s <= v,
            (None, Some(e)) => v < e,
            (None, None) => false,
        }
    }
}
impl Overlaps<Range<i64>> for Range<Option<i64>> {
    fn overlaps(&self, v: Range<i64>) -> bool {
        self.overlaps(v.start) || self.overlaps(v.end)
    }
}