use itertools::Itertools; use super::{AccountName, Datestamp, Decimal, Spanned, UnitName}; mod parse; pub use parse::parse_ledger; mod print; pub use print::print_ledger; #[derive(Clone, Debug, PartialEq, PartialOrd, Ord, Eq)] pub struct Change { pub account: Spanned, pub amount: Spanned, pub balance: Option>, pub unit: Spanned, } #[derive(Clone, Debug, PartialEq, PartialOrd, Eq, Ord)] pub struct Transaction { pub datestamp: Datestamp, pub title: Option, pub annotations: Vec, pub changes: Vec>, } impl Transaction { pub fn modifies(&self, account: AccountName) -> bool { self.changes.iter().any(|b| b.account.as_ref() == &account) } pub fn change_for(&self, account: AccountName) -> Option<&Spanned> { self.changes.iter().find(|b| b.account.as_ref() == &account) } pub fn split_changes( &self, account: AccountName, ) -> Option<(&Spanned, impl Iterator>)> { let index = self .changes .iter() .position(|b| b.account.as_ref() == &account)?; Some(( &self.changes[index], self.changes[0..index] .iter() .chain(self.changes[index + 1..].iter()), )) } pub fn is_mono_unit(&self) -> bool { self.changes.iter().unique_by(|b| *b.unit).count() == 1 } pub fn mono_unit(&self) -> Option { let mut it = self.changes.iter().unique_by(|b| *b.unit); let uniq = it.next()?; it.next().is_none().then_some(*uniq.unit) } pub fn get_annotation(&self, label: &str) -> Option<&str> { for anno in self.annotations.iter() { if let Some(body) = anno.strip_prefix(label) { return Some(body) } } None } } #[derive(Debug, PartialEq, Eq, PartialOrd, Ord)] pub enum LedgerEntry { Transaction(Spanned), Comment(Spanned), } impl LedgerEntry { pub fn as_transaction(&self) -> Option<&Spanned> { match self { Self::Transaction(tx) => Some(tx), _ => None, } } pub fn as_transaction_mut(&mut self) -> Option<&mut Spanned> { match self { Self::Transaction(tx) => Some(tx), _ => None, } } pub fn span(&self) -> super::Span { match self { Self::Transaction(ts) => ts.span(), Self::Comment(c) => c.span(), } } }