diff options
Diffstat (limited to 'apps/cassiopeia/src/data.rs')
-rw-r--r-- | apps/cassiopeia/src/data.rs | 142 |
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()), + } } } |