okane_core/report/
context.rs1use bumpalo::Bump;
2use bumpalo_intern::direct::{DirectInternStore, FromInterned, InternedStr, StoredValue};
3
4use crate::report::commodity::CommodityTag;
5
6use super::commodity::CommodityStore;
7
8#[derive(Debug, PartialEq, Eq, Hash, Clone, Copy)]
10pub struct Account<'arena>(InternedStr<'arena>);
11
12impl<'arena> FromInterned<'arena> for Account<'arena> {
13 fn from_interned(v: InternedStr<'arena>) -> Self {
14 Self(v)
15 }
16
17 fn as_interned(&self) -> InternedStr<'arena> {
18 self.0
19 }
20}
21
22impl<'arena> Account<'arena> {
23 pub fn as_str(&self) -> &'arena str {
25 self.0.as_str()
26 }
27}
28
29pub(super) type AccountStore<'arena> = DirectInternStore<'arena, Account<'arena>>;
31
32pub struct ReportContext<'ctx> {
34 pub(super) arena: &'ctx Bump,
35 pub(super) accounts: AccountStore<'ctx>,
36 pub(super) commodities: CommodityStore<'ctx>,
37}
38
39impl<'ctx> ReportContext<'ctx> {
40 pub fn new(arena: &'ctx Bump) -> Self {
42 let accounts = AccountStore::new(arena);
43 let commodities = CommodityStore::new(arena);
44 Self {
45 arena,
46 accounts,
47 commodities,
48 }
49 }
50
51 pub(super) fn all_accounts_unsorted(&self) -> impl Iterator<Item = Account<'ctx>> + '_ {
53 self.accounts.iter().filter_map(|x| match x {
54 StoredValue::Canonical(x) => Some(x),
55 StoredValue::Alias { .. } => None,
56 })
57 }
58 pub(super) fn all_accounts(&self) -> Vec<Account<'ctx>> {
60 let mut r: Vec<Account<'ctx>> = self.all_accounts_unsorted().collect();
61 r.sort_unstable_by_key(|x| x.as_str());
62 r
63 }
64
65 pub fn account(&self, value: &str) -> Option<Account<'ctx>> {
67 self.accounts.resolve(value)
68 }
69
70 pub fn commodity(&self, value: &str) -> Option<CommodityTag<'ctx>> {
72 self.commodities.resolve(value)
73 }
74
75 pub fn commodity_store(&self) -> &CommodityStore<'ctx> {
77 &self.commodities
78 }
79 pub fn commodity_store_mut(&mut self) -> &mut CommodityStore<'ctx> {
81 &mut self.commodities
82 }
83}
84
85#[cfg(test)]
86mod tests {
87 use pretty_assertions::assert_eq;
88
89 use super::*;
90
91 #[test]
92 fn context_all_accounts() {
93 let arena = Bump::new();
94 let mut ctx = ReportContext::new(&arena);
95 let want = vec![
96 ctx.accounts.ensure("Account 1"),
97 ctx.accounts.ensure("Account 2"),
98 ctx.accounts.ensure("Account 2:Sub account"),
99 ctx.accounts.ensure("Account 3"),
100 ctx.accounts.ensure("資産:りんご"),
103 ctx.accounts.ensure("資産:バナナ"),
104 ctx.accounts.ensure("資産:吉祥寺"),
105 ];
106
107 let got = ctx.all_accounts();
108
109 assert_eq!(want, got);
110 }
111
112 #[test]
113 fn context_sccount() {
114 let arena = Bump::new();
115 let mut ctx = ReportContext::new(&arena);
116 let a1 = ctx.accounts.ensure("Account 1");
117 let a3 = ctx.accounts.ensure("Account 3");
118
119 assert_eq!(Some(a1), ctx.account("Account 1"));
120 assert_eq!(None, ctx.account("Account 2"));
121 assert_eq!(Some(a3), ctx.account("Account 3"));
122 }
123}