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
|
// god is dead and we have killed him and consequently std::time::Instant doesn't work on wasm
use chrono::prelude::*;
use wasm_bindgen::prelude::*;
struct Reading {
time: DateTime<Local>,
queue_size: u32,
}
#[derive(Default)]
pub struct History {
data: Vec<Reading>,
}
pub enum NoETA {
Pending,
Fuck,
}
// Duration doesn't impl Mul<f32> so we have to do percents
const RECENCY_PERCENT: i32 = 20;
impl History {
pub fn record(&mut self, queue_size: u32) {
let redundant = match self.data.last() {
Some(last) => queue_size == last.queue_size,
None => false,
};
if !redundant {
self.data.push(Reading {
time: Local::now(),
queue_size,
});
}
}
pub fn completion_time(&self) -> Result<js_sys::Date, NoETA> {
let weighted_average_step_time = self
.data
.iter()
.zip(self.data.iter().skip(1))
.map(|(one, two)| {
// queue velocity should ideally be measured in distance per time,
// but the units wind up fucky (reciprocal duration not implemented)
// so instead we use time per distance
if one.time > two.time {
return Err(NoETA::Fuck);
}
let delta_time = two.time - one.time;
let delta_queue = match one.queue_size.checked_sub(two.queue_size) {
Some(d) => d,
None => return Err(NoETA::Fuck),
};
Ok(delta_time / delta_queue as i32)
})
.reduce(|previous, current| match (previous, current) {
(Ok(previous), Ok(current)) => {
let previous_term = previous * (100 - RECENCY_PERCENT) / 100;
let current_term = current * RECENCY_PERCENT / 100;
Ok(previous_term + current_term)
}
(Err(e), _) => Err(e),
(_, Err(e)) => Err(e),
})
.ok_or(NoETA::Pending)??;
let &Reading {
time: last_time,
queue_size: last_size,
} = self.data.last().ok_or(NoETA::Pending)?;
let remaining_duration = weighted_average_step_time * last_size as i32;
let completion_time = last_time + remaining_duration;
let completion_time_gmt = completion_time.timestamp_millis();
Ok(js_sys::Date::new(&JsValue::from(
completion_time_gmt as f64,
)))
}
}
|