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 assert2::{assert, let_assert};
use super::*;
use crate::date::DateTime;
fn task_event(time: (u32, u32, u32), proj: &str, secs: u64) -> TaskEvent {
let_assert!(Ok(datetime) = DateTime::new((2022, 2, 17), time));
TaskEvent::new(
datetime,
proj,
Duration::from_secs(secs)
)
}
#[test]
fn test_hour_new() {
let hour = Hour::default();
assert!(hour.is_empty());
assert!(None == hour.iter().next());
assert!(hour.remain() == 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!(None == hour.add(dur.clone()));
assert!(!hour.is_empty());
assert!(Some(&dur) == hour.iter().next());
}
#[test]
fn test_hour_add_partial_remain() {
let mut hour = Hour::default();
let dur = task_event((8, 0, 0), "foo", 300);
assert!(None == hour.add(dur.clone()));
assert!(hour.remain() == Duration::from_secs(3300));
let used: Duration = hour.iter().map(|d| d.duration()).sum();
assert!(hour.remain() == 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!(None == hour.add(dur.clone()));
}
assert!(!hour.is_empty());
for (dur, hdur) in durs.iter().zip(hour.iter()) {
assert!(hdur == 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!(None == hour.add(dur.clone()));
}
assert!(hour.remain() == Duration::from_secs(2700));
let used: Duration = hour.iter().map(|d| d.duration()).sum();
assert!(hour.remain() == 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!(None == hour.add(dur1.clone()));
let_assert!(Some(_d2) = hour.add(dur2.clone()));
let expect = [dur1, task_event((8, 55, 0), "bar", 300)];
for (dur, hdur) in expect.iter().zip(hour.iter()) {
assert!(hdur == 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!(None == hour.add(dur1.clone()));
let_assert!(Some(dur) = hour.add(dur2.clone()));
assert!(dur == remain);
assert!(hour.remain() == Duration::from_secs(0));
let used: Duration = hour.iter().map(|d| d.duration()).sum();
assert!(used == Duration::from_secs(3600));
}
}