hypertask_engine/
engine.rs1use crate::error::*;
2use crate::id::Id;
3use crate::prop::Prop;
4use crate::rpn::StackMachine;
5use crate::tag::Tag;
6use crate::task::{FinalisedTask, Task};
7use chrono::prelude::*;
8
9#[derive(Debug, Deserialize, Serialize)]
10pub enum Mutation {
11 SetProp(Prop),
12 SetTag(Tag),
13}
14
15#[derive(Debug, Deserialize, Serialize)]
16pub enum Query {
17 Id(Id),
18 Tag(Tag),
19}
20
21#[derive(Debug, Deserialize, Serialize)]
22pub enum Command {
23 Create(Vec<Mutation>),
24 Read(Vec<Query>),
25 Update(Vec<Query>, Vec<Mutation>),
26 Delete(Vec<Query>),
27}
28
29pub trait HyperTaskEngineContext<TaskIterator: Iterator<Item = HyperTaskResult<Task>>> {
30 fn finalize_mutations(&self) -> HyperTaskResult<()>;
31 fn generate_id(&mut self) -> String;
32 fn get_now(&self) -> DateTime<Utc>;
33 fn get_stack_machine(&self) -> HyperTaskResult<StackMachine>;
34 fn get_task_iterator(&self) -> HyperTaskResult<TaskIterator>;
35 fn put_task(&mut self, task: &Task) -> HyperTaskResult<()>;
36}
37
38struct TaskEngine<
39 InputIterator: Iterator<Item = HyperTaskResult<Task>>,
40 Context: HyperTaskEngineContext<InputIterator>,
41> {
42 command: Command,
43 input_iterator: InputIterator,
44 context: Context,
45 now: DateTime<Utc>,
46 done: bool,
47}
48
49impl<
50 InputIterator: Iterator<Item = HyperTaskResult<Task>>,
51 Context: HyperTaskEngineContext<InputIterator>,
52 > TaskEngine<InputIterator, Context>
53{
54 pub fn new(command: Command, context: Context) -> HyperTaskResult<Self> {
55 let now = context.get_now();
56 let input_iterator = context.get_task_iterator()?;
57
58 Ok(Self {
59 command,
60 input_iterator,
61 context,
62 now,
63 done: false,
64 })
65 }
66
67 fn yield_next_task(&mut self) -> Option<HyperTaskResult<Task>> {
68 if self.done {
69 return None;
70 }
71
72 match &self.command {
73 Command::Read(queries) => match self.input_iterator.next()? {
74 Err(e) => Some(Err(e)),
75 Ok(next_task) => {
76 if queries.is_empty() || next_task.satisfies_queries(&queries) {
77 Some(Ok(next_task))
78 } else {
79 self.yield_next_task()
80 }
81 }
82 },
83
84 Command::Create(mutations) => {
85 let mut new_task = Task::generate(&mut self.context);
86 new_task.apply_mutations(mutations, &self.now);
87
88 self.done = true;
89
90 Some(self.context.put_task(&new_task).map(|_| new_task))
91 }
92
93 Command::Update(queries, mutations) => match self.input_iterator.next()? {
94 Err(e) => Some(Err(e)),
95 Ok(mut next_task) => {
96 if next_task.satisfies_queries(&queries) {
97 next_task.apply_mutations(mutations, &self.now);
98
99 Some(self.context.put_task(&next_task).map(|_| next_task))
100 } else {
101 self.yield_next_task()
102 }
103 }
104 },
105
106 Command::Delete(_) => {
107 panic!("fuck you");
108 }
109 }
110 }
111}
112
113impl<
114 InputIterator: Iterator<Item = HyperTaskResult<Task>>,
115 Context: HyperTaskEngineContext<InputIterator>,
116 > Iterator for TaskEngine<InputIterator, Context>
117{
118 type Item = HyperTaskResult<Task>;
119
120 fn next(&mut self) -> Option<Self::Item> {
121 let next_task = self.yield_next_task();
122
123 if next_task.is_some() {
124 return next_task;
125 }
126
127 if let Command::Read(_) = self.command {
128 return None;
129 }
130
131 match self.context.finalize_mutations() {
132 Ok(_) => None,
133 Err(e) => Some(Err(e)),
134 }
135 }
136}
137
138pub fn run<InputIterator, Context>(
139 command: Command,
140 context: Context,
141) -> HyperTaskResult<Vec<FinalisedTask>>
142where
143 InputIterator: Iterator<Item = HyperTaskResult<Task>>,
144 Context: HyperTaskEngineContext<InputIterator>,
145{
146 let mut stack_machine = context.get_stack_machine()?;
147
148 let mut task_collection = TaskEngine::new(command, context)?
149 .map(|task_result| task_result.and_then(|task| task.finalise(&mut stack_machine)))
150 .filter(|finalised_task| {
151 if let Ok(ft) = finalised_task {
152 (ft.get_score() - 0.0).abs() > std::f64::EPSILON
153 } else {
154 true
155 }
156 })
157 .collect::<HyperTaskResult<Vec<FinalisedTask>>>()?;
158
159 task_collection.sort_unstable();
160
161 Ok(task_collection)
162}