1use std::fmt::Debug;
2
3use dyn_clone::DynClone;
4
5use crate::environment::Environment;
6use crate::ir::NumVal::{Number, Unsure};
7use crate::ir::*;
8use crate::resolver::{resolve_date, resolve_range};
9
10pub trait Filter<T>: Debug + DynClone {
11 fn check(&self, value: &T, env: Option<&Environment>) -> bool;
12 fn filter(&self, values: Vec<T>, env: Option<&Environment>) -> Vec<T> {
13 let mut res = vec![];
15 for value in values {
16 if self.check(&value, env) {
17 res.push(value);
18 }
19 }
20 res
21 }
22}
23
24dyn_clone::clone_trait_object!(<T> Filter<T>);
25
26#[derive(Debug, Clone)]
27pub enum Op {
28 OR,
29 And,
30}
31
32pub type BDF<T> = Box<dyn Filter<T>>;
33
34#[derive(Debug, Clone)]
35pub struct BinFilt<T: Debug> {
36 pub lhs: BDF<T>,
37 pub rhs: BDF<T>,
38 pub op: Op,
39}
40
41impl<T: Debug + Clone> Filter<T> for BinFilt<T> {
42 fn check(&self, value: &T, env: Option<&Environment>) -> bool {
43 match self.op {
44 Op::OR => self.lhs.check(value, env) || self.rhs.check(value, env),
45 Op::And => self.lhs.check(value, env) && self.rhs.check(value, env),
46 }
47 }
48}
49
50#[derive(Debug, Clone)]
51pub struct ExcludeFilt<T> {
52 pub target: BDF<T>,
53}
54
55impl<T: Debug + Clone> ExcludeFilt<T> {
56 pub fn new(target: BDF<T>) -> Self {
57 ExcludeFilt { target }
58 }
59}
60
61impl<T: Debug + Clone> Filter<T> for ExcludeFilt<T> {
62 fn check(&self, value: &T, env: Option<&Environment>) -> bool {
63 !self.target.check(value, env)
64 }
65}
66
67impl Filter<NumVal> for NumRange {
68 fn check(&self, value: &NumVal, _env: Option<&Environment>) -> bool {
69 match *value {
70 Number(target) => match (&self.start, &self.end) {
71 (Unsure, Unsure) => true,
72 (Unsure, Number(nd)) => target <= *nd,
73 (Number(st), Unsure) => target >= *st,
74 (Number(st), Number(nd)) => target >= *st && target <= *nd,
75 },
76 _ => true,
77 }
78 }
79}
80
81impl Filter<NumVal> for NumVal {
82 fn check(&self, value: &NumVal, _env: Option<&Environment>) -> bool {
83 if matches!(self, Unsure) {
84 true
85 } else {
86 self == value
87 }
88 }
89}
90
91impl Filter<ExactDate> for ExactRange {
92 fn check(&self, value: &ExactDate, _env: Option<&Environment>) -> bool {
93 match self {
94 ExactRange::TimeRange(tr) => {
95 let start = tr.start.date.to_chrono().unwrap();
97 let end = tr.end.date.to_chrono().unwrap();
98 let target = value.to_chrono().unwrap();
99 target >= start && target <= end
100 }
101 ExactRange::AllDay(date) => date == value,
102 }
103 }
104}
105
106impl Filter<Date> for Range {
107 fn check(&self, value: &Date, env: Option<&Environment>) -> bool {
108 let exact_range = resolve_range(self, env.unwrap()).unwrap();
110 let exact_date = resolve_date(value, env.unwrap()).unwrap();
111 exact_range.check(&exact_date, env)
112 }
113}
114
115impl Filter<NumVal> for FlexField {
116 fn check(&self, value: &NumVal, env: Option<&Environment>) -> bool {
117 match self {
118 FlexField::NumRange(nr) => nr.check(value, env),
119 FlexField::NumVal(nv) => nv.check(value, env),
120 }
121 }
122}
123
124impl Filter<ExactDate> for FlexDate {
125 fn check(&self, value: &ExactDate, env: Option<&Environment>) -> bool {
126 self.year.check(&Number(value.year as i64), env)
127 && self.month.check(&Number(value.month as i64), env)
128 && self.day.check(&Number(value.day as i64), env)
129 }
130}
131
132impl Filter<Date> for FlexDate {
133 fn check(&self, value: &Date, env: Option<&Environment>) -> bool {
134 let exact_date = resolve_date(value, env.unwrap()).unwrap();
135 self.year.check(&Number(exact_date.year as i64), env)
136 && self.month.check(&Number(exact_date.month as i64), env)
137 && self.day.check(&Number(exact_date.day as i64), env)
138 }
139}
140
141mod tests {
144 use super::*;
145 use crate::ir::Range;
146 use crate::ir::TimeRange;
147 #[test]
148 fn test_flex_date() {
149 let fd = FlexDate {
150 year: Box::new(Number(2023)),
151 month: Box::new(NumRange {
152 start: Number(6),
153 end: Number(10),
154 }),
155 day: Box::new(NumRange {
156 start: Number(8),
157 end: Number(15),
158 }),
159 };
160 assert!(fd.check(
161 &ExactDate {
162 year: 2023,
163 month: 6,
164 day: 8
165 },
166 None
167 ));
168 assert!(!fd.check(
169 &ExactDate {
170 year: 2023,
171 month: 6,
172 day: 7
173 },
174 None
175 ));
176 assert!(!fd.check(
177 &ExactDate {
178 year: 2023,
179 month: 5,
180 day: 8
181 },
182 None
183 ));
184 assert!(!fd.check(
185 &ExactDate {
186 year: 2022,
187 month: 6,
188 day: 8
189 },
190 None
191 ));
192 }
193
194 #[test]
195 fn test_time_range() {
196 let trange = TimeRange {
197 start: DateTime::from_ymd(2020, 1, 3),
198 end: DateTime::from_ymd(2020, 2, 1),
199 };
200 eprintln!("{:?}", trange);
201 let range = Range::Time(trange);
202 let env = Environment::from_exact(ExactDateTime::from_ymd_hms(2020, 1, 1, 1, 1, 1));
203 assert!(range.check(&Date::from_ymd(2020, 1, 3), Some(&env)));
204 assert!(!range.check(&Date::from_ymd(2020, 1, 2), Some(&env)));
205 assert!(range.check(&Date::from_ymd(2020, 2, 1), Some(&env)));
206 }
207 #[test]
208 fn test_tree() {
209 let orfilt = BinFilt {
211 lhs: Box::new(NumRange {
212 start: Number(1),
213 end: Number(5),
214 }),
215 rhs: Box::new(NumRange {
216 start: Number(10),
217 end: Number(15),
218 }),
219 op: Op::OR,
220 };
221 assert!(orfilt.check(&Number(1), None));
222 assert!(!orfilt.check(&Number(8), None));
223 assert!(orfilt.check(&Number(13), None));
224 let andfilt = BinFilt {
225 lhs: Box::new(NumRange {
226 start: Number(1),
227 end: Number(8),
228 }),
229 rhs: Box::new(NumRange {
230 start: Number(3),
231 end: Unsure,
232 }),
233 op: Op::And,
234 };
235 assert!(!andfilt.check(&Number(1), None));
236 assert!(andfilt.check(&Number(8), None));
237 assert!(!andfilt.check(&Number(13), None));
238 let combfilt = BinFilt {
239 lhs: Box::new(ExcludeFilt {
240 target: Box::new(orfilt),
241 }),
242 rhs: Box::new(andfilt),
243 op: Op::OR,
244 };
245 assert!(combfilt.check(&Number(3), None));
246 assert!(combfilt.check(&Number(9), None));
247 assert!(!combfilt.check(&Number(2), None));
248 }
249}