use std::time::Duration;
use crate::TaskEvent;
fn hour() -> Duration { Duration::from_secs(3600) }
pub struct DayHours {
start: usize,
hours: Vec<Hour>
}
impl DayHours {
pub fn start(&self) -> usize { self.start }
pub fn end(&self) -> usize { self.start() + self.hours.len() - 1 }
pub fn num_hours(&self) -> usize { self.hours.len() }
pub fn add(&mut self, event: TaskEvent) {
let hour = event.hour();
if self.hours.is_empty() {
self.start = hour;
self.hours.push(Hour::default());
}
if hour > self.end() {
(0..(hour - self.end())).for_each(|_| self.hours.push(Hour::default()));
}
let start = self.start();
if let Some(the_hour) = self.hours.get_mut(hour - start) {
if let Some(ev) = the_hour.add(event) {
self.add(ev);
}
}
}
pub fn iter(&self) -> impl Iterator<Item = &'_ Hour> { self.hours.iter() }
}
impl Default for DayHours {
fn default() -> Self { Self { start: 0, hours: Vec::new() } }
}
#[derive(Debug, Clone, Eq, PartialEq, PartialOrd)]
pub struct Hour {
events: Vec<TaskEvent>,
offset: Duration
}
impl Hour {
pub fn is_empty(&self) -> bool { self.events.is_empty() }
pub fn iter(&self) -> impl Iterator<Item = &'_ TaskEvent> { self.events.iter() }
pub fn remain(&self) -> Duration { hour() - self.offset }
pub fn add(&mut self, event: TaskEvent) -> Option<TaskEvent> {
self.offset = Duration::from_secs(u64::from(event.second_offset()));
if event.duration() >= self.remain() {
let (first, next) = event.split(self.remain())?;
self.events.push(first);
self.offset = hour();
Some(next)
}
else {
self.offset += event.duration();
self.events.push(event);
None
}
}
}
impl Default for Hour {
fn default() -> Self { Self { events: vec![], offset: Duration::default() } }
}
#[cfg(test)]
mod tests {
use spectral::prelude::*;
use super::*;
use crate::date::DateTime;
fn task_event(time: (u32, u32, u32), proj: &str, secs: u64) -> TaskEvent {
TaskEvent::new(
DateTime::new((2022, 2, 17), time).unwrap(),
proj,
Duration::from_secs(secs)
)
}
#[test]
fn test_hour_new() {
let hour = Hour::default();
assert_that!(hour.is_empty()).is_equal_to(true);
assert_that!(hour.iter().next()).is_none();
assert_that!(hour.remain()).is_equal_to(Duration::from_secs(3600));
}
#[test]
fn test_hour_add_partial() {
let mut hour = Hour::default();
let dur = task_event((8, 0, 0), "foo", 300);
assert_that!(hour.add(dur.clone())).is_none();
assert_that!(hour.is_empty()).is_equal_to(false);
assert_that!(hour.iter().next()).contains(&dur);
}
#[test]
fn test_hour_add_partial_remain() {
let mut hour = Hour::default();
let dur = task_event((8, 0, 0), "foo", 300);
assert_that!(hour.add(dur.clone())).is_none();
assert_that!(hour.remain()).is_equal_to(Duration::from_secs(3300));
let used: Duration = hour.iter().map(|d| d.duration()).sum();
assert_that!(hour.remain()).is_equal_to(Duration::from_secs(3600) - used);
}
#[test]
fn test_hour_add_partial_again() {
let mut hour = Hour::default();
let durs = [
task_event((8, 0, 0), "foo", 300),
task_event((8, 5, 0), "bar", 600)
];
for dur in durs.iter() {
assert_that!(hour.add(dur.clone())).is_none();
}
assert_that!(hour.is_empty()).is_equal_to(false);
for (dur, hdur) in durs.iter().zip(hour.iter()) {
assert_that!(hdur).is_equal_to(&dur);
}
}
#[test]
fn test_hour_add_partial_again_remain() {
let mut hour = Hour::default();
let durs = [
task_event((8, 0, 0), "foo", 300),
task_event((8, 5, 0), "bar", 600)
];
for dur in durs.iter() {
assert_that!(hour.add(dur.clone())).is_none();
}
assert_that!(hour.remain()).is_equal_to(Duration::from_secs(2700));
let used: Duration = hour.iter().map(|d| d.duration()).sum();
assert_that!(hour.remain()).is_equal_to(Duration::from_secs(3600) - used);
}
#[test]
fn test_hour_add_overflow() {
let mut hour = Hour::default();
let dur1 = task_event((8, 0, 0), "foo", 3300);
let dur2 = task_event((8, 55, 0), "bar", 650);
assert_that!(hour.add(dur1.clone())).is_none();
assert_that!(hour.add(dur2.clone())).is_some();
let expect = [dur1, task_event((8, 55, 0), "bar", 300)];
for (dur, hdur) in expect.iter().zip(hour.iter()) {
assert_that!(hdur).is_equal_to(&dur);
}
}
#[test]
fn test_hour_add_overflow_remain() {
let mut hour = Hour::default();
let dur1 = task_event((8, 0, 0), "foo", 3300);
let dur2 = task_event((8, 55, 0), "bar", 650);
let remain = task_event((9, 0, 0), "bar", 350);
assert_that!(hour.add(dur1.clone())).is_none();
assert_that!(hour.add(dur2.clone())).contains(remain);
assert_that!(hour.remain()).is_equal_to(Duration::from_secs(0));
let used: Duration = hour.iter().map(|d| d.duration()).sum();
assert_that!(used).is_equal_to(Duration::from_secs(3600));
}
}