// 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, queue_size: u32, } #[derive(Default)] pub struct History { data: Vec, } pub enum NoETA { Pending, Fuck, } // Duration doesn't impl Mul 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 { 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, ))) } }