use crate::{format::LineCfg, Date, Time, TimeFile}; use std::collections::BTreeMap; /// A set of IR parsed items that makes up a whole cass file pub(crate) type IrStream = Vec; /// Intermediate representation for parsing and generating files /// /// The CASS IR is largely based on the output of the parser's /// [`LineCfg`](crate::format::LineCfg), but with concrete types used /// in the data layer (namely [`Date`][date] and [`Time`][time]), /// while also keeping track of the line numbers to allow idempotent /// file changes. /// /// Something not yet implemented is comment pass-through (this needs /// to happen in the parser first), but will likely be implemented in /// a future version. /// /// [date]: crate::Date /// [time]: crate::Time #[derive(Debug, Clone)] pub(crate) struct IrItem { pub(crate) tt: IrType, pub(crate) lo: usize, } /// Disambiguate between different IR line types with their payload #[derive(Debug, Clone)] pub(crate) enum IrType { /// A line with parsed header information Header(BTreeMap), /// Start a session at a given timestapm Start(Time), /// Stop a session at a given timestamp Stop(Time), /// Invoice a block of previous work Invoice(Date), /// An item that gets ignored Ignore, } /// Generate a stream of IR items from the raw parser output pub(crate) fn generate_ir(buf: impl Iterator) -> IrStream { buf.enumerate().fold(vec![], |mut buf, (lo, item)| { #[cfg_attr(rustfmt, rustfmt_skip)] buf.push(match item { LineCfg::Header(map) => IrItem { tt: IrType::Header(map), lo }, LineCfg::Start(Some(time)) => IrItem { tt: IrType::Start(time.into()), lo }, LineCfg::Stop(Some(time)) => IrItem { tt: IrType::Stop(time.into()), lo }, LineCfg::Invoice(Some(date)) => IrItem { tt: IrType::Invoice(date.into()), lo }, LineCfg::Ignore => IrItem { tt: IrType::Ignore, lo }, _ => IrItem { tt: IrType::Ignore, lo }, }); buf }) } pub(crate) trait MakeIr { /// Make a new IR line from an object fn make_ir(&self) -> IrType; }