From d40e014aebc778939ae8d9afae225b7d4f6cc949 Mon Sep 17 00:00:00 2001 From: Mx Kookie Date: Fri, 11 Dec 2020 17:58:39 +0000 Subject: cassiopeia: adding more types to the time file abstraction --- apps/cassiopeia/src/data.rs | 66 ++++++++++++++++++++++++++++++++---- apps/cassiopeia/src/format/mod.rs | 7 ++-- apps/cassiopeia/src/format/parser.rs | 22 ++++++------ apps/cassiopeia/src/main.rs | 3 +- 4 files changed, 77 insertions(+), 21 deletions(-) (limited to 'apps/cassiopeia/src') diff --git a/apps/cassiopeia/src/data.rs b/apps/cassiopeia/src/data.rs index 8ebc67f016c5..3911345109ca 100644 --- a/apps/cassiopeia/src/data.rs +++ b/apps/cassiopeia/src/data.rs @@ -5,25 +5,79 @@ //! analysis tasks. use crate::format::LineCfg; -use chrono::{Date, DateTime, FixedOffset as Offset}; +use chrono::{DateTime, Duration, FixedOffset as Offset, NaiveDate}; use std::collections::BTreeMap; -#[derive(Default)] +#[derive(Debug, Default)] pub struct TimeFile { + /// Raw line buffers to echo back into the file + lines: Vec, + /// A parsed header structure header: BTreeMap, + /// A parsed session structure sessions: Vec, - invoices: Vec>, + /// A parsed invoice list + invoices: Vec, } impl TimeFile { - pub(crate) fn append(self, line: LineCfg) -> Self { - println!("{:?}", line); + pub(crate) fn append(mut self, line: LineCfg) -> Self { + let lo = self.lines.len(); + match line { + LineCfg::Header(ref header) => self.header = header.clone(), + LineCfg::Start(Some(time)) => self.sessions.push(Session::start(time, lo)), + LineCfg::Stop(Some(time)) => self.get_last_session().stop(time, lo), + LineCfg::Invoice(Some(date)) => self.invoices.push(Invoice::new(date, lo)), + _ => {} + } + self.lines.push(line); self } + + fn get_last_session(&mut self) -> &mut Session { + self.sessions.last_mut().unwrap() + } } +#[derive(Debug)] pub struct Session { start: DateTime, - stop: DateTime, + stop: Option>, + /// Track the lines this session took place in + lines: (usize, usize), +} + +impl Session { + /// Create a new session with a start time + fn start(start: DateTime, line: usize) -> Self { + Self { + start, + stop: None, + lines: (line, 0), + } + } + + /// Finalise a session with a stop time + fn stop(&mut self, stop: DateTime, line: usize) { + self.stop = Some(stop); + self.lines.1 = line; + } + + /// Get the length of the session, if it was already finished + pub fn length(&self) -> Option { + self.stop.map(|stop| stop - self.start) + } +} + +#[derive(Debug)] +pub struct Invoice { + date: NaiveDate, + line: usize, +} + +impl Invoice { + fn new(date: NaiveDate, line: usize) -> Self { + Self { date, line } + } } diff --git a/apps/cassiopeia/src/format/mod.rs b/apps/cassiopeia/src/format/mod.rs index beab2f7aac66..bac0445d8387 100644 --- a/apps/cassiopeia/src/format/mod.rs +++ b/apps/cassiopeia/src/format/mod.rs @@ -9,7 +9,10 @@ pub(crate) use parser::LineCfg; use crate::TimeFile; use std::{fs::File, io::Read}; -pub(crate) fn load_file(path: &str) { +/// The cassiopeia parser/generator version to be written back into the file +pub const CASS_VERSION: &str = env!("CARGO_PKG_VERSION"); + +pub(crate) fn load_file(path: &str) -> TimeFile { let mut f = File::open(path).unwrap(); let mut content = String::new(); f.read_to_string(&mut content).unwrap(); @@ -21,5 +24,5 @@ pub(crate) fn load_file(path: &str) { .map(|line| lexer::lex(line)) .map(|lex| parser::parse(lex)) .filter(|line| line.valid()) - .fold(TimeFile::default(), |file, line| file.append(line)); + .fold(TimeFile::default(), |file, line| file.append(line)) } diff --git a/apps/cassiopeia/src/format/parser.rs b/apps/cassiopeia/src/format/parser.rs index cc4b1b7c77df..bb2c56be0f33 100644 --- a/apps/cassiopeia/src/format/parser.rs +++ b/apps/cassiopeia/src/format/parser.rs @@ -4,8 +4,7 @@ //! parsed time file. use crate::format::{LineLexer, LineToken, Token}; -use chrono::{DateTime, FixedOffset as Offset}; -use logos::Lexer; +use chrono::{NaiveDate, DateTime, FixedOffset as Offset}; use std::collections::BTreeMap; use std::iter::Iterator; @@ -19,9 +18,7 @@ pub enum LineCfg { /// A session stop line with a date and time Stop(Option>), /// An invoice line with a date - Invoice(Option>), - /// An empty line - Empty, + Invoice(Option), /// A temporary value that is invalid #[doc(hidden)] Ignore, @@ -39,7 +36,7 @@ impl LineCfg { pub(crate) fn parse<'l>(lex: LineLexer<'l>) -> LineCfg { use LineCfg::*; use Token as T; - + #[cfg_attr(rustfmt, rustfmt_skip)] lex.get_all().into_iter().fold(Ignore, |cfg, tok| match (cfg, tok) { // If the first token is a comment, we ignore it @@ -52,13 +49,10 @@ pub(crate) fn parse<'l>(lex: LineLexer<'l>) -> LineCfg { // If the first token _was_ a keyword, fill in the data (Header(map), LineToken { tt: T::HeaderData, slice }) => Header(append_data(map, slice)), - (Start(_), LineToken { tt: T::Date, slice }) => Start(parse_date(slice)), - (Stop(_), LineToken { tt: T::Date, slice }) => Stop(parse_date(slice)), + (Start(_), LineToken { tt: T::Date, slice }) => Start(parse_datetime(slice)), + (Stop(_), LineToken { tt: T::Date, slice }) => Stop(parse_datetime(slice)), (Invoice(_), LineToken { tt: T::Date, slice }) => Invoice(parse_date(slice)), - // Pass empty lines through, - (Empty, _) => Empty, - // Ignore everything else (which will be filtered) _ => Ignore, }) @@ -70,9 +64,13 @@ fn append_data(mut map: BTreeMap, slice: &str) -> BTreeMap Option> { +fn parse_datetime(slice: &str) -> Option> { Some( DateTime::parse_from_str(slice, "%Y-%m-%d %H:%M:%S%:z") .expect("Failed to parse date; invalid format!"), ) } + +fn parse_date(slice: &str) -> Option { + Some(NaiveDate::parse_from_str(slice, "%Y-%m-%d").expect("Failed to parse date; invalid format!")) +} diff --git a/apps/cassiopeia/src/main.rs b/apps/cassiopeia/src/main.rs index b28f3c3438f7..ff942731c3d5 100644 --- a/apps/cassiopeia/src/main.rs +++ b/apps/cassiopeia/src/main.rs @@ -4,5 +4,6 @@ mod data; pub use data::{TimeFile, Session}; fn main() { - format::load_file("/home/projects/clients/nyantec-nix-workshops/time.cass") + let file = format::load_file("/home/projects/clients/nyantec-nix-workshops/time.cass"); + } -- cgit v1.2.3