1use std::time::Duration;
28
29#[doc(inline)]
30use crate::date::DateTime;
31#[doc(inline)]
32use crate::entry::Entry;
33
34#[derive(Debug, Clone, Eq, Ord, PartialOrd, PartialEq)]
36pub struct TaskEvent {
37 start: DateTime,
39 proj: Option<String>,
41 dur: Duration
43}
44
45impl TaskEvent {
46 pub fn new<'a, OS>(start: DateTime, proj: OS, dur: Duration) -> Self
48 where
49 OS: Into<Option<&'a str>>
50 {
51 Self { start, proj: proj.into().map(ToString::to_string), dur }
52 }
53
54 pub fn from_entry(entry: &Entry) -> Self {
56 Self::new(entry.date_time(), entry.project(), Duration::default())
57 }
58
59 #[rustfmt::skip]
64 pub fn split(&self, dur: Duration) -> Option<(Self, Self)> {
65 Some((
66 Self {
67 start: self.start,
68 proj: self.proj(),
69 dur
70 },
71 Self {
72 start: (self.start + dur).ok()?,
73 proj: self.proj(),
74 dur: self.dur - dur
75 }
76 ))
77 }
78
79 pub fn proj(&self) -> Option<String> { self.proj.as_ref().cloned() }
81
82 pub fn project(&self) -> String { self.proj().unwrap_or_default() }
84
85 pub fn hour(&self) -> usize { self.start.hour() as usize }
87
88 pub fn start(&self) -> &DateTime { &self.start }
90
91 pub fn add_dur(&mut self, dur: Duration) { self.dur += dur; }
93
94 pub fn duration(&self) -> Duration { self.dur }
96
97 pub fn as_secs(&self) -> u64 { self.dur.as_secs() }
99
100 pub fn second_offset(&self) -> u32 { self.start.second_offset() }
102}
103
104#[cfg(test)]
105mod tests {
106 use assert2::{assert, let_assert};
107
108 use super::*;
109 use crate::DateTime;
110
111 #[test]
112 fn test_new_with_project() {
113 let_assert!(Ok(datetime) = DateTime::new((2022, 3, 20), (12, 34, 56)));
114 let task = TaskEvent::new(
115 datetime,
116 "proja",
117 Duration::from_secs(305)
118 );
119 let_assert!(Some(proj) = task.proj());
120 assert!(proj == String::from("proja"));
121 assert!(task.project() == String::from("proja"));
122 let_assert!(Ok(expect_start) = DateTime::new((2022, 3, 20), (12, 34, 56)));
123 assert!(task.start() == &expect_start);
124 assert!(task.hour() == 12);
125 assert!(task.duration() == Duration::from_secs(305));
126 }
127
128 #[test]
129 fn test_new_without_project() {
130 let_assert!(Ok(datetime) = DateTime::new((2022, 3, 20), (13, 24, 56)));
131 let task = TaskEvent::new(
132 datetime,
133 None,
134 Duration::from_secs(255)
135 );
136 assert!(task.proj() == None);
137 assert!(task.project() == String::new());
138 let_assert!(Ok(expect_start) = DateTime::new((2022, 3, 20), (13, 24, 56)));
139 assert!(task.start() == &expect_start);
140 assert!(task.hour() == 13);
141 assert!(task.duration() == Duration::from_secs(255));
142 }
143
144 #[test]
145 fn test_add_dur() {
146 let_assert!(Ok(datetime) = DateTime::new((2022, 3, 20), (12, 34, 56)));
147 let mut task = TaskEvent::new(
148 datetime,
149 "proja",
150 Duration::from_secs(305)
151 );
152
153 assert!(task.as_secs() == 305, "Initial value");
154
155 task.add_dur(Duration::from_secs(3600));
156 assert!(task.as_secs() == 3905, "After add_dur");
157 assert!(task.duration() == Duration::from_secs(3905));
158 }
159
160 #[test]
161 fn test_second_offset() {
162 let_assert!(Ok(datetime) = DateTime::new((2022, 3, 20), (12, 34, 56)));
163 let task = TaskEvent::new(
164 datetime,
165 "proja",
166 Duration::from_secs(305)
167 );
168
169 assert!(task.second_offset() == 34 * 60 + 56);
170 }
171
172 #[test]
173 fn test_split() {
174 let_assert!(Ok(datetime) = DateTime::new((2022, 3, 20), (12, 34, 56)));
175 let task = TaskEvent::new(
176 datetime,
177 "proja",
178 Duration::from_secs(600)
179 );
180
181 let_assert!(Some((first, second)) = task.split(Duration::from_secs(250)));
182
183 let_assert!(Ok(expected) = DateTime::new((2022, 3, 20), (12, 34, 56)));
184 assert!(first.start() == &expected);
185 assert!(first.duration() == Duration::from_secs(250));
186
187 let_assert!(Ok(expected) = DateTime::new((2022, 3, 20), (12, 39, 6)));
188 assert!(second.start() == &expected);
189 assert!(second.duration() == Duration::from_secs(350));
190 }
191}