-
Notifications
You must be signed in to change notification settings - Fork 0
/
mod.rs
82 lines (72 loc) · 1.93 KB
/
mod.rs
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
use rustyline::{history::DefaultHistory, Editor};
use timetable_optimizer_lib::data::Timetable;
pub mod exclude_teacher;
pub mod free_workdays;
pub mod max_end_time;
pub mod max_gap_between_courses;
pub mod min_start_time;
pub mod no_course_between;
pub trait Filter {
fn filter(&self, timetable: &Timetable) -> bool;
}
fn parse_with_key<F, T>(
spec: &str,
key: &str,
parse_fn: F,
) -> Option<Result<Box<dyn Filter>, String>>
where
F: FnOnce(&str) -> Result<T, String>,
T: Filter + 'static,
{
match spec.strip_prefix(&(key.to_string() + "=")) {
Some(value) => Some(match parse_fn(value) {
Ok(filter) => Ok(Box::new(filter)),
Err(e) => Err(e),
}),
None => None,
}
}
fn parse_filter(spec: &str) -> Result<Box<dyn Filter>, String> {
let parsers = &[
min_start_time::try_parse,
max_end_time::try_parse,
free_workdays::try_parse,
max_gap_between_courses::try_parse,
exclude_teacher::try_parse,
no_course_between::try_parse,
];
parsers
.iter()
.find_map(|parser| parser(spec))
.ok_or_else(|| format!("Invalid filter specification: {spec}"))?
}
pub fn prompt_filters() -> Vec<Box<dyn Filter>> {
let mut rl = Editor::<(), DefaultHistory>::new().unwrap();
let hist_file = "out/history.txt";
rl.load_history(hist_file).ok();
let specs = rl.readline("Enter filter: ").unwrap();
rl.add_history_entry(specs.as_str()).unwrap();
rl.save_history(hist_file).unwrap();
let filters_parsed = specs
.trim()
.split(' ')
.filter(|spec| !spec.is_empty())
.map(parse_filter)
.collect();
match filters_parsed {
Ok(filters) => filters,
Err(e) => {
eprintln!("Error parsing filter: {e}");
prompt_filters()
}
}
}
pub fn filter_timetables(
timetables: Vec<Timetable>,
filters: Vec<Box<dyn Filter>>,
) -> Vec<Timetable> {
timetables
.into_iter()
.filter(|timetable| filters.iter().all(|filter| filter.filter(timetable)))
.collect()
}