ledger.rs 2.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899
  1. use itertools::Itertools;
  2. use super::{AccountName, Datestamp, Decimal, Spanned, UnitName};
  3. mod parse;
  4. pub use parse::parse_ledger;
  5. mod print;
  6. pub use print::print_ledger;
  7. #[derive(Clone, Debug, PartialEq, PartialOrd, Ord, Eq)]
  8. pub struct Change {
  9. pub account: Spanned<AccountName>,
  10. pub amount: Spanned<Decimal>,
  11. pub balance: Option<Spanned<Decimal>>,
  12. pub unit: Spanned<UnitName>,
  13. }
  14. #[derive(Clone, Debug, PartialEq, PartialOrd, Eq, Ord)]
  15. pub struct Transaction {
  16. pub datestamp: Datestamp,
  17. pub title: Option<String>,
  18. pub annotations: Vec<String>,
  19. pub changes: Vec<Spanned<Change>>,
  20. }
  21. impl Transaction {
  22. pub fn modifies(&self, account: AccountName) -> bool {
  23. self.changes.iter().any(|b| b.account.as_ref() == &account)
  24. }
  25. pub fn change_for(&self, account: AccountName) -> Option<&Spanned<Change>> {
  26. self.changes.iter().find(|b| b.account.as_ref() == &account)
  27. }
  28. pub fn split_changes(
  29. &self,
  30. account: AccountName,
  31. ) -> Option<(&Spanned<Change>, impl Iterator<Item = &Spanned<Change>>)> {
  32. let index = self
  33. .changes
  34. .iter()
  35. .position(|b| b.account.as_ref() == &account)?;
  36. Some((
  37. &self.changes[index],
  38. self.changes[0..index]
  39. .iter()
  40. .chain(self.changes[index + 1..].iter()),
  41. ))
  42. }
  43. pub fn is_mono_unit(&self) -> bool {
  44. self.changes.iter().unique_by(|b| *b.unit).count() == 1
  45. }
  46. pub fn mono_unit(&self) -> Option<UnitName> {
  47. let mut it = self.changes.iter().unique_by(|b| *b.unit);
  48. let uniq = it.next()?;
  49. it.next().is_none().then_some(*uniq.unit)
  50. }
  51. pub fn get_annotation(&self, label: &str) -> Option<&str> {
  52. for anno in self.annotations.iter() {
  53. if let Some(body) = anno.strip_prefix(label) {
  54. return Some(body)
  55. }
  56. }
  57. None
  58. }
  59. }
  60. #[derive(Debug, PartialEq, Eq, PartialOrd, Ord)]
  61. pub enum LedgerEntry {
  62. Transaction(Spanned<Transaction>),
  63. Comment(Spanned<String>),
  64. }
  65. impl LedgerEntry {
  66. pub fn as_transaction(&self) -> Option<&Spanned<Transaction>> {
  67. match self {
  68. Self::Transaction(tx) => Some(tx),
  69. _ => None,
  70. }
  71. }
  72. pub fn as_transaction_mut(&mut self) -> Option<&mut Spanned<Transaction>> {
  73. match self {
  74. Self::Transaction(tx) => Some(tx),
  75. _ => None,
  76. }
  77. }
  78. pub fn span(&self) -> super::Span {
  79. match self {
  80. Self::Transaction(ts) => ts.span(),
  81. Self::Comment(c) => c.span(),
  82. }
  83. }
  84. }