1use super::prelude::*;
4use std::collections::HashSet;
5use strum::IntoEnumIterator;
6use strum_macros::EnumIter;
7
8#[derive(Hash, Eq, PartialEq, EnumIter, Debug)]
10pub enum Check {
11 Overlaps,
13 UnknownTags,
15 ConfirmDeletion,
18}
19
20#[derive(Debug)]
22pub struct Checks(HashSet<Check>);
23
24impl Checks {
25 pub fn all() -> Self {
27 Self(HashSet::from_iter(Check::iter()))
28 }
29 pub fn all_but(check: Check) -> Self {
31 Self(HashSet::from_iter(Check::iter().filter(|c| *c != check)))
32 }
33 pub fn omit() -> Self {
35 Self(HashSet::new())
36 }
37 pub fn no_confirm() -> Self {
39 Self(HashSet::from([Check::Overlaps]))
40 }
41 pub fn has(&self, check: Check) -> bool {
43 self.0.contains(&check)
44 }
45 pub fn check(
52 &self,
53 jobs: &Jobs,
54 pos: Option<usize>,
55 job: &Job,
56 context: &Context,
57 ) -> Result<(), Error> {
58 let mut warnings = Vec::new();
59
60 if let Some(end) = job.end {
62 if job.start >= end {
63 return Err(Error::EndBeforeStart(job.start, end));
64 }
65 }
66
67 if self.has(Check::Overlaps) {
69 let mut overlapping = JobList::new_from(jobs);
70 for (n, j) in jobs.iter().enumerate() {
71 if !j.is_deleted() {
72 if let Some(pos) = pos {
73 if n != pos && job.overlaps(j, context) {
74 overlapping.push(n, j);
75 }
76 } else if job.overlaps(j, context) {
77 overlapping.push(n, j);
78 }
79 }
80 }
81 if !overlapping.is_empty() {
82 warnings.push(Warning::Overlaps {
83 new: job.clone(),
84 existing: overlapping.into(),
85 });
86 }
87 }
88
89 if self.has(Check::UnknownTags) {
91 let tags = jobs.tags();
92 let unknown_tags: TagSet = job.tags.filter(|tag| !tags.contains(tag));
93 if !unknown_tags.0.is_empty() {
94 warnings.push(Warning::UnknownTags(unknown_tags));
95 }
96 }
97
98 jobs.configuration.get_checked(&job.tags)?;
100
101 if !warnings.is_empty() {
103 return Err(Error::Warnings(warnings));
104 }
105 Ok(())
106 }
107}