use crate::cost::{BookedCost, Cost, CostNumber, CostSpec};
use crate::directive::{
Balance, Close, Commodity, Custom, Directive, Document, Event, MetaValue, Note, Open, Pad,
Posting, Price, PriceAnnotation, PriceKind, Query, Transaction,
};
use crate::identifiers::{Account, Currency, Link, Tag};
use crate::{Amount, IncompleteAmount, InternedStr, ShiftSpans, Span};
impl<K, V: ShiftSpans, S> ShiftSpans for std::collections::HashMap<K, V, S> {
fn shift_spans<F: Fn(&mut Span)>(&mut self, shift: &F) {
for value in self.values_mut() {
value.shift_spans(shift);
}
}
}
crate::impl_shift_spans_noop!(
rust_decimal::Decimal,
jiff::civil::Date,
char,
f32,
f64,
InternedStr,
Account,
Currency,
Tag,
Link,
);
impl ShiftSpans for Amount {
fn shift_spans<F: Fn(&mut Span)>(&mut self, shift: &F) {
let Self { number, currency } = self;
number.shift_spans(shift);
currency.shift_spans(shift);
}
}
impl ShiftSpans for IncompleteAmount {
fn shift_spans<F: Fn(&mut Span)>(&mut self, shift: &F) {
match self {
Self::Complete(amount) => amount.shift_spans(shift),
Self::NumberOnly(number) => number.shift_spans(shift),
Self::CurrencyOnly(currency) => currency.shift_spans(shift),
}
}
}
impl ShiftSpans for Cost {
fn shift_spans<F: Fn(&mut Span)>(&mut self, shift: &F) {
let Self {
number,
currency,
date,
label,
} = self;
number.shift_spans(shift);
currency.shift_spans(shift);
date.shift_spans(shift);
label.shift_spans(shift);
}
}
impl ShiftSpans for CostSpec {
fn shift_spans<F: Fn(&mut Span)>(&mut self, shift: &F) {
let Self {
number,
currency,
date,
label,
merge,
} = self;
number.shift_spans(shift);
currency.shift_spans(shift);
date.shift_spans(shift);
label.shift_spans(shift);
merge.shift_spans(shift);
}
}
impl ShiftSpans for CostNumber {
fn shift_spans<F: Fn(&mut Span)>(&mut self, shift: &F) {
match self {
Self::PerUnit { value } | Self::Total { value } => value.shift_spans(shift),
Self::PerUnitFromTotal(booked) => booked.shift_spans(shift),
}
}
}
impl ShiftSpans for BookedCost {
fn shift_spans<F: Fn(&mut Span)>(&mut self, shift: &F) {
let Self { per_unit, total } = self;
per_unit.shift_spans(shift);
total.shift_spans(shift);
}
}
impl ShiftSpans for PriceAnnotation {
fn shift_spans<F: Fn(&mut Span)>(&mut self, shift: &F) {
let Self { kind, amount } = self;
kind.shift_spans(shift);
amount.shift_spans(shift);
}
}
impl ShiftSpans for PriceKind {
fn shift_spans<F: Fn(&mut Span)>(&mut self, _: &F) {
match self {
Self::Unit | Self::Total => {}
}
}
}
impl ShiftSpans for MetaValue {
fn shift_spans<F: Fn(&mut Span)>(&mut self, shift: &F) {
match self {
Self::String(s) => s.shift_spans(shift),
Self::Account(a) => a.shift_spans(shift),
Self::Currency(c) => c.shift_spans(shift),
Self::Tag(t) => t.shift_spans(shift),
Self::Link(l) => l.shift_spans(shift),
Self::Date(d) => d.shift_spans(shift),
Self::Number(n) => n.shift_spans(shift),
Self::Bool(b) => b.shift_spans(shift),
Self::Amount(a) => a.shift_spans(shift),
Self::None => {}
}
}
}
impl ShiftSpans for Posting {
fn shift_spans<F: Fn(&mut Span)>(&mut self, shift: &F) {
let Self {
account,
units,
cost,
price,
flag,
meta,
comments,
trailing_comments,
} = self;
account.shift_spans(shift);
units.shift_spans(shift);
cost.shift_spans(shift);
price.shift_spans(shift);
flag.shift_spans(shift);
meta.shift_spans(shift);
comments.shift_spans(shift);
trailing_comments.shift_spans(shift);
}
}
impl ShiftSpans for Transaction {
fn shift_spans<F: Fn(&mut Span)>(&mut self, shift: &F) {
let Self {
date,
flag,
payee,
narration,
tags,
links,
meta,
postings,
trailing_comments,
} = self;
date.shift_spans(shift);
flag.shift_spans(shift);
payee.shift_spans(shift);
narration.shift_spans(shift);
tags.shift_spans(shift);
links.shift_spans(shift);
meta.shift_spans(shift);
postings.shift_spans(shift);
trailing_comments.shift_spans(shift);
}
}
impl ShiftSpans for Open {
fn shift_spans<F: Fn(&mut Span)>(&mut self, shift: &F) {
let Self {
date,
account,
currencies,
booking,
meta,
} = self;
date.shift_spans(shift);
account.shift_spans(shift);
currencies.shift_spans(shift);
booking.shift_spans(shift);
meta.shift_spans(shift);
}
}
impl ShiftSpans for Close {
fn shift_spans<F: Fn(&mut Span)>(&mut self, shift: &F) {
let Self {
date,
account,
meta,
} = self;
date.shift_spans(shift);
account.shift_spans(shift);
meta.shift_spans(shift);
}
}
impl ShiftSpans for Balance {
fn shift_spans<F: Fn(&mut Span)>(&mut self, shift: &F) {
let Self {
date,
account,
amount,
tolerance,
meta,
} = self;
date.shift_spans(shift);
account.shift_spans(shift);
amount.shift_spans(shift);
tolerance.shift_spans(shift);
meta.shift_spans(shift);
}
}
impl ShiftSpans for Pad {
fn shift_spans<F: Fn(&mut Span)>(&mut self, shift: &F) {
let Self {
date,
account,
source_account,
meta,
} = self;
date.shift_spans(shift);
account.shift_spans(shift);
source_account.shift_spans(shift);
meta.shift_spans(shift);
}
}
impl ShiftSpans for Note {
fn shift_spans<F: Fn(&mut Span)>(&mut self, shift: &F) {
let Self {
date,
account,
comment,
meta,
} = self;
date.shift_spans(shift);
account.shift_spans(shift);
comment.shift_spans(shift);
meta.shift_spans(shift);
}
}
impl ShiftSpans for Document {
fn shift_spans<F: Fn(&mut Span)>(&mut self, shift: &F) {
let Self {
date,
account,
path,
tags,
links,
meta,
} = self;
date.shift_spans(shift);
account.shift_spans(shift);
path.shift_spans(shift);
tags.shift_spans(shift);
links.shift_spans(shift);
meta.shift_spans(shift);
}
}
impl ShiftSpans for Price {
fn shift_spans<F: Fn(&mut Span)>(&mut self, shift: &F) {
let Self {
date,
currency,
amount,
meta,
} = self;
date.shift_spans(shift);
currency.shift_spans(shift);
amount.shift_spans(shift);
meta.shift_spans(shift);
}
}
impl ShiftSpans for Custom {
fn shift_spans<F: Fn(&mut Span)>(&mut self, shift: &F) {
let Self {
date,
custom_type,
values,
meta,
} = self;
date.shift_spans(shift);
custom_type.shift_spans(shift);
values.shift_spans(shift);
meta.shift_spans(shift);
}
}
impl ShiftSpans for Event {
fn shift_spans<F: Fn(&mut Span)>(&mut self, shift: &F) {
let Self {
date,
event_type,
value,
meta,
} = self;
date.shift_spans(shift);
event_type.shift_spans(shift);
value.shift_spans(shift);
meta.shift_spans(shift);
}
}
impl ShiftSpans for Query {
fn shift_spans<F: Fn(&mut Span)>(&mut self, shift: &F) {
let Self {
date,
name,
query,
meta,
} = self;
date.shift_spans(shift);
name.shift_spans(shift);
query.shift_spans(shift);
meta.shift_spans(shift);
}
}
impl ShiftSpans for Commodity {
fn shift_spans<F: Fn(&mut Span)>(&mut self, shift: &F) {
let Self {
date,
currency,
meta,
} = self;
date.shift_spans(shift);
currency.shift_spans(shift);
meta.shift_spans(shift);
}
}
impl ShiftSpans for Directive {
fn shift_spans<F: Fn(&mut Span)>(&mut self, shift: &F) {
match self {
Self::Transaction(t) => t.shift_spans(shift),
Self::Balance(b) => b.shift_spans(shift),
Self::Open(o) => o.shift_spans(shift),
Self::Close(c) => c.shift_spans(shift),
Self::Commodity(c) => c.shift_spans(shift),
Self::Pad(p) => p.shift_spans(shift),
Self::Event(e) => e.shift_spans(shift),
Self::Query(q) => q.shift_spans(shift),
Self::Note(n) => n.shift_spans(shift),
Self::Document(d) => d.shift_spans(shift),
Self::Price(p) => p.shift_spans(shift),
Self::Custom(c) => c.shift_spans(shift),
}
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::{NaiveDate, Spanned};
#[test]
fn directive_shift_spans_propagates_into_posting_spans() {
use crate::Amount;
use rust_decimal_macros::dec;
let posting = Spanned::new(
Posting::new("Assets:Bank", Amount::new(dec!(100), "USD")),
Span::new(50, 75),
);
let txn = Transaction {
date: NaiveDate::new(2024, 1, 1).unwrap(),
flag: '*',
payee: None,
narration: "Test".into(),
tags: Vec::new(),
links: Vec::new(),
meta: crate::Metadata::default(),
postings: vec![posting],
trailing_comments: Vec::new(),
};
let mut d = Directive::Transaction(txn);
d.shift_spans(&|s: &mut Span| {
s.start += 10;
s.end += 10;
});
if let Directive::Transaction(t) = d {
assert_eq!(t.postings[0].span, Span::new(60, 85));
} else {
unreachable!();
}
}
#[test]
fn metadata_shift_spans_dispatches_via_value_impl() {
use crate::Amount;
use rust_decimal_macros::dec;
let mut meta = crate::Metadata::default();
meta.insert(
"amt".to_string(),
MetaValue::Amount(Amount::new(dec!(1), "USD")),
);
let shift = |_: &mut Span| {
};
meta.shift_spans(&shift);
}
}