use rustledger_core::intern::{InternedStr, StringInterner};
use rustledger_core::{Directive, IncompleteAmount, MetaValue, Metadata};
use rustledger_parser::Spanned;
pub fn reintern_directives(directives: &mut [Spanned<Directive>]) -> usize {
let mut interner = StringInterner::with_capacity(1024);
let mut dedup_count = 0;
for spanned in directives.iter_mut() {
dedup_count += reintern_directive(&mut spanned.value, &mut interner);
}
dedup_count
}
pub fn reintern_plain_directives(directives: &mut [Directive]) -> usize {
let mut interner = StringInterner::with_capacity(1024);
let mut dedup_count = 0;
for directive in directives.iter_mut() {
dedup_count += reintern_directive(directive, &mut interner);
}
dedup_count
}
fn do_intern(s: &mut InternedStr, interner: &mut StringInterner) -> bool {
let (new, was_new) = interner.intern_with_status(s.as_str());
*s = new;
!was_new
}
fn intern_typed_vec<T>(
v: &mut [T],
interner: &mut StringInterner,
dedup_count: &mut usize,
get_inner: fn(&mut T) -> &mut InternedStr,
) {
for s in v.iter_mut() {
if do_intern(get_inner(s), interner) {
*dedup_count += 1;
}
}
}
fn intern_meta(meta: &mut Metadata, interner: &mut StringInterner, dedup_count: &mut usize) {
for value in meta.values_mut() {
match value {
MetaValue::Account(a) => {
if do_intern(a.as_interned_mut(), interner) {
*dedup_count += 1;
}
}
MetaValue::Currency(c) => {
if do_intern(c.as_interned_mut(), interner) {
*dedup_count += 1;
}
}
MetaValue::Tag(t) => {
if do_intern(t.as_interned_mut(), interner) {
*dedup_count += 1;
}
}
MetaValue::Link(l) => {
if do_intern(l.as_interned_mut(), interner) {
*dedup_count += 1;
}
}
MetaValue::Amount(a) => {
if do_intern(a.currency.as_interned_mut(), interner) {
*dedup_count += 1;
}
}
MetaValue::String(_)
| MetaValue::Number(_)
| MetaValue::Date(_)
| MetaValue::Bool(_)
| MetaValue::None => {}
}
}
}
fn reintern_directive(directive: &mut Directive, interner: &mut StringInterner) -> usize {
let mut dedup_count = 0;
match directive {
Directive::Transaction(txn) => {
if let Some(ref mut payee) = txn.payee
&& do_intern(payee, interner)
{
dedup_count += 1;
}
if do_intern(&mut txn.narration, interner) {
dedup_count += 1;
}
intern_typed_vec(
&mut txn.tags,
interner,
&mut dedup_count,
rustledger_core::Tag::as_interned_mut,
);
intern_typed_vec(
&mut txn.links,
interner,
&mut dedup_count,
rustledger_core::Link::as_interned_mut,
);
intern_meta(&mut txn.meta, interner, &mut dedup_count);
for posting in &mut txn.postings {
if do_intern(posting.account.as_interned_mut(), interner) {
dedup_count += 1;
}
intern_meta(&mut posting.meta, interner, &mut dedup_count);
if let Some(ref mut units) = posting.units {
match units {
IncompleteAmount::Complete(amt) => {
if do_intern(amt.currency.as_interned_mut(), interner) {
dedup_count += 1;
}
}
IncompleteAmount::CurrencyOnly(cur) => {
if do_intern(cur.as_interned_mut(), interner) {
dedup_count += 1;
}
}
IncompleteAmount::NumberOnly(_) => {}
}
}
if let Some(ref mut cost) = posting.cost
&& let Some(ref mut cur) = cost.currency
&& do_intern(cur.as_interned_mut(), interner)
{
dedup_count += 1;
}
if let Some(price) = &mut posting.price {
match &mut price.amount {
Some(IncompleteAmount::Complete(amt)) => {
if do_intern(amt.currency.as_interned_mut(), interner) {
dedup_count += 1;
}
}
Some(IncompleteAmount::CurrencyOnly(cur)) => {
if do_intern(cur.as_interned_mut(), interner) {
dedup_count += 1;
}
}
Some(IncompleteAmount::NumberOnly(_)) | None => {}
}
}
}
}
Directive::Balance(bal) => {
if do_intern(bal.account.as_interned_mut(), interner) {
dedup_count += 1;
}
if do_intern(bal.amount.currency.as_interned_mut(), interner) {
dedup_count += 1;
}
intern_meta(&mut bal.meta, interner, &mut dedup_count);
}
Directive::Open(open) => {
if do_intern(open.account.as_interned_mut(), interner) {
dedup_count += 1;
}
intern_typed_vec(
&mut open.currencies,
interner,
&mut dedup_count,
rustledger_core::Currency::as_interned_mut,
);
intern_meta(&mut open.meta, interner, &mut dedup_count);
}
Directive::Close(close) => {
if do_intern(close.account.as_interned_mut(), interner) {
dedup_count += 1;
}
intern_meta(&mut close.meta, interner, &mut dedup_count);
}
Directive::Commodity(comm) => {
if do_intern(comm.currency.as_interned_mut(), interner) {
dedup_count += 1;
}
intern_meta(&mut comm.meta, interner, &mut dedup_count);
}
Directive::Pad(pad) => {
if do_intern(pad.account.as_interned_mut(), interner) {
dedup_count += 1;
}
if do_intern(pad.source_account.as_interned_mut(), interner) {
dedup_count += 1;
}
intern_meta(&mut pad.meta, interner, &mut dedup_count);
}
Directive::Note(note) => {
if do_intern(note.account.as_interned_mut(), interner) {
dedup_count += 1;
}
intern_meta(&mut note.meta, interner, &mut dedup_count);
}
Directive::Document(doc) => {
if do_intern(doc.account.as_interned_mut(), interner) {
dedup_count += 1;
}
intern_typed_vec(
&mut doc.tags,
interner,
&mut dedup_count,
rustledger_core::Tag::as_interned_mut,
);
intern_typed_vec(
&mut doc.links,
interner,
&mut dedup_count,
rustledger_core::Link::as_interned_mut,
);
intern_meta(&mut doc.meta, interner, &mut dedup_count);
}
Directive::Price(price) => {
if do_intern(price.currency.as_interned_mut(), interner) {
dedup_count += 1;
}
if do_intern(price.amount.currency.as_interned_mut(), interner) {
dedup_count += 1;
}
intern_meta(&mut price.meta, interner, &mut dedup_count);
}
Directive::Event(e) => {
intern_meta(&mut e.meta, interner, &mut dedup_count);
}
Directive::Query(q) => {
intern_meta(&mut q.meta, interner, &mut dedup_count);
}
Directive::Custom(c) => {
intern_meta(&mut c.meta, interner, &mut dedup_count);
}
}
dedup_count
}