use bumpalo::Bump;
use bumpalo_intern::direct::{DirectInternStore, FromInterned, InternedStr, StoredValue};
use crate::report::commodity::CommodityTag;
use super::commodity::CommodityStore;
#[derive(Debug, PartialEq, Eq, Hash, Clone, Copy)]
pub struct Account<'arena>(InternedStr<'arena>);
impl<'arena> FromInterned<'arena> for Account<'arena> {
fn from_interned(v: InternedStr<'arena>) -> Self {
Self(v)
}
fn as_interned(&self) -> InternedStr<'arena> {
self.0
}
}
impl<'arena> Account<'arena> {
pub fn as_str(&self) -> &'arena str {
self.0.as_str()
}
}
pub(super) type AccountStore<'arena> = DirectInternStore<'arena, Account<'arena>>;
pub struct ReportContext<'ctx> {
pub(super) arena: &'ctx Bump,
pub(super) accounts: AccountStore<'ctx>,
pub(super) commodities: CommodityStore<'ctx>,
}
impl<'ctx> ReportContext<'ctx> {
pub fn new(arena: &'ctx Bump) -> Self {
let accounts = AccountStore::new(arena);
let commodities = CommodityStore::new(arena);
Self {
arena,
accounts,
commodities,
}
}
pub(super) fn all_accounts_unsorted(&self) -> impl Iterator<Item = Account<'ctx>> + '_ {
self.accounts.iter().filter_map(|x| match x {
StoredValue::Canonical(x) => Some(x),
StoredValue::Alias { .. } => None,
})
}
pub(super) fn all_accounts(&self) -> Vec<Account<'ctx>> {
let mut r: Vec<Account<'ctx>> = self.all_accounts_unsorted().collect();
r.sort_unstable_by_key(|x| x.as_str());
r
}
pub fn account(&self, value: &str) -> Option<Account<'ctx>> {
self.accounts.resolve(value)
}
pub fn commodity(&self, value: &str) -> Option<CommodityTag<'ctx>> {
self.commodities.resolve(value)
}
pub fn commodity_store(&self) -> &CommodityStore<'ctx> {
&self.commodities
}
pub fn commodity_store_mut(&mut self) -> &mut CommodityStore<'ctx> {
&mut self.commodities
}
}
#[cfg(test)]
mod tests {
use pretty_assertions::assert_eq;
use super::*;
#[test]
fn context_all_accounts() {
let arena = Bump::new();
let mut ctx = ReportContext::new(&arena);
let want = vec![
ctx.accounts.ensure("Account 1"),
ctx.accounts.ensure("Account 2"),
ctx.accounts.ensure("Account 2:Sub account"),
ctx.accounts.ensure("Account 3"),
ctx.accounts.ensure("資産:りんご"),
ctx.accounts.ensure("資産:バナナ"),
ctx.accounts.ensure("資産:吉祥寺"),
];
let got = ctx.all_accounts();
assert_eq!(want, got);
}
#[test]
fn context_sccount() {
let arena = Bump::new();
let mut ctx = ReportContext::new(&arena);
let a1 = ctx.accounts.ensure("Account 1");
let a3 = ctx.accounts.ensure("Account 3");
assert_eq!(Some(a1), ctx.account("Account 1"));
assert_eq!(None, ctx.account("Account 2"));
assert_eq!(Some(a3), ctx.account("Account 3"));
}
}