aboutsummaryrefslogtreecommitdiff
path: root/apps/cassiopeia/src/data.rs
diff options
context:
space:
mode:
Diffstat (limited to 'apps/cassiopeia/src/data.rs')
-rw-r--r--apps/cassiopeia/src/data.rs142
1 files changed, 36 insertions, 106 deletions
diff --git a/apps/cassiopeia/src/data.rs b/apps/cassiopeia/src/data.rs
index 188c0255203d..3034d020b1e9 100644
--- a/apps/cassiopeia/src/data.rs
+++ b/apps/cassiopeia/src/data.rs
@@ -5,7 +5,9 @@
//! analysis tasks.
use crate::{
+ error::{ParseError, ParseResult, UserResult},
format::ir::{IrItem, IrType, MakeIr},
+ timeline::{Entry, Timeline},
Date, Time,
};
use chrono::{DateTime, Duration, FixedOffset as Offset, Local, NaiveDate};
@@ -14,116 +16,42 @@ use std::collections::BTreeMap;
#[derive(Debug, Default)]
pub struct TimeFile {
/// A parsed header structure
- header: BTreeMap<String, String>,
- /// A parsed session structure
- sessions: Vec<Session>,
- /// A parsed invoice list
- invoices: Vec<Invoice>,
+ pub(crate) header: BTreeMap<String, String>,
+ /// A parsed timeline of events
+ pub(crate) timeline: Timeline,
}
impl TimeFile {
- pub(crate) fn append(&mut self, line: IrItem) {
+ /// Append entries to the timeline from the parsed IR
+ ///
+ /// Report any errors that occur back to the parser, that will
+ /// print a message to the user and terminate the program.
+ pub(crate) fn append(&mut self, line: IrItem) -> ParseResult<()> {
match line {
IrItem {
tt: IrType::Header(ref header),
..
- } => self.header = header.clone(),
+ } => Ok(header.iter().for_each(|(k, v)| {
+ self.header.insert(k.clone(), v.clone());
+ })),
IrItem {
tt: IrType::Start(time),
lo,
- } => self.sessions.push(Session::start(time.into())),
+ } => Ok(self.timeline.start(time).map(|_| ())?),
IrItem {
tt: IrType::Stop(time),
lo,
- } => self.get_last_session().unwrap().stop(time.into()),
+ } => Ok(self.timeline.stop(time).map(|_| ())?),
IrItem {
tt: IrType::Invoice(date),
lo,
- } => self.invoices.push(Invoice::new(date.into())),
- _ => {}
- }
- }
-
- fn get_last_session(&mut self) -> Option<&mut Session> {
- self.sessions.last_mut()
- }
-
- fn get_last_invoice(&mut self) -> Option<&mut Invoice> {
- self.invoices.last_mut()
- }
-
- /// Start a new session (optionally 15-minute rounded)
- ///
- /// This function returns the new session object that will have to
- /// be turned into an IR line to be written back into the file
- pub(crate) fn start(&mut self, round: bool) -> Option<Session> {
- // Check if the last session was closed
- match self.get_last_session() {
- Some(s) if !s.finished() => return None,
- _ => {}
- }
-
- // Create a new time
- let now = if round {
- Time::now().round()
- } else {
- Time::now()
- };
-
- Some(Session::start(now))
- }
-
- /// Stop the last session that was started, returning a completed
- /// session
- pub(crate) fn stop(&mut self, round: bool) -> Option<Session> {
- match self.get_last_session() {
- Some(s) if s.finished() => return None,
- None => return None,
- _ => {}
- }
-
- // Create a new time
- let now = if round {
- Time::now().round()
- } else {
- Time::now()
- };
-
- self.get_last_session().cloned().map(|mut s| {
- s.stop(now);
- s
- })
- }
-
- /// Add a new invoice block to the time file
- pub(crate) fn invoice(&mut self) -> Option<Invoice> {
- let today = Date::today();
-
- let last_sess = self.get_last_session().cloned();
-
- match self.get_last_invoice() {
- // Check if _today_ there has been already an invoice
- Some(i) if i.date == today => return None,
-
- // Check if since the last invoice there has been at least
- // _one_ terminated session.
- Some(i)
- if !last_sess
- .map(|s| !s.stop.map(|s| s.after(&i.date)).unwrap_or(false))
- .unwrap_or(false) =>
- {
- return None
- }
-
- // Otherwise, we create an invoice
- _ => {}
+ } => Ok(self.timeline.invoice(date).map(|_| ())?),
+ _ => Err(ParseError::Unknown),
}
-
- Some(Invoice::new(today))
}
}
-#[derive(Clone, Debug)]
+#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord)]
pub struct Session {
start: Time,
stop: Option<Time>,
@@ -131,12 +59,12 @@ pub struct Session {
impl Session {
/// Create a new session with a start time
- fn start(start: Time) -> Self {
+ pub(crate) fn start(start: Time) -> Self {
Self { start, stop: None }
}
/// Finalise a session with a stop time
- fn stop(&mut self, stop: Time) {
+ pub(crate) fn stop(&mut self, stop: Time) {
self.stop = Some(stop);
}
@@ -151,28 +79,30 @@ impl Session {
}
}
-impl MakeIr for Session {
- fn make_ir(&self) -> IrType {
- match self.stop {
- Some(ref time) => IrType::Stop(time.clone()),
- None => IrType::Start(self.start.clone()),
- }
- }
-}
-
-#[derive(Debug)]
+#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord)]
pub struct Invoice {
- date: Date,
+ pub(crate) date: Date,
}
impl Invoice {
- fn new(date: Date) -> Self {
+ pub(crate) fn new(date: Date) -> Self {
Self { date }
}
}
-impl MakeIr for Invoice {
+/// Changes to the timeline are encoded in a delta
+pub(crate) enum Delta {
+ Start(Time),
+ Stop(Time),
+ Invoice(Date),
+}
+
+impl MakeIr for Delta {
fn make_ir(&self) -> IrType {
- IrType::Invoice(self.date.clone())
+ match self {
+ Self::Start(ref time) => IrType::Start(time.clone()),
+ Self::Stop(ref time) => IrType::Stop(time.clone()),
+ Self::Invoice(ref date) => IrType::Invoice(date.clone()),
+ }
}
}