1pub mod decoration;
4pub mod display;
5pub mod expr;
6pub mod plain;
7pub mod pretty_decimal;
8pub mod tracked;
9
10use std::{borrow::Cow, fmt};
11
12use bounded_static::ToStatic;
13use chrono::{NaiveDate, NaiveDateTime};
14use derive_where::derive_where;
15
16#[cfg(test)]
17use bounded_static::ToBoundedStatic;
18
19use decoration::Decoration;
20
21#[derive_where(Debug, PartialEq, Eq)]
23pub enum LedgerEntry<'i, Deco: Decoration> {
24 Txn(Transaction<'i, Deco>),
26 Comment(TopLevelComment<'i>),
28 ApplyTag(ApplyTag<'i>),
30 EndApplyTag,
32 Include(IncludeFile<'i>),
34 Account(AccountDeclaration<'i>),
36 Commodity(CommodityDeclaration<'i>),
38}
39
40impl LedgerEntry<'_, plain::Ident> {
41 #[cfg(test)]
42 pub(crate) fn to_static(&self) -> LedgerEntry<'static, plain::Ident> {
43 match self {
44 LedgerEntry::Txn(v) => LedgerEntry::Txn(v.to_static()),
45 LedgerEntry::Comment(v) => LedgerEntry::Comment(v.to_static()),
46 LedgerEntry::ApplyTag(v) => LedgerEntry::ApplyTag(v.to_static()),
47 LedgerEntry::EndApplyTag => LedgerEntry::EndApplyTag,
48 LedgerEntry::Include(v) => LedgerEntry::Include(v.to_static()),
49 LedgerEntry::Account(v) => LedgerEntry::Account(v.to_static()),
50 LedgerEntry::Commodity(v) => LedgerEntry::Commodity(v.to_static()),
51 }
52 }
53}
54
55#[derive(Debug, PartialEq, Eq, ToStatic)]
57pub struct TopLevelComment<'i>(pub Cow<'i, str>);
58
59#[derive(Debug, PartialEq, Eq, ToStatic)]
61pub struct ApplyTag<'i> {
62 pub key: Cow<'i, str>,
63 pub value: Option<MetadataValue<'i>>,
64}
65
66#[derive(Debug, PartialEq, Eq, ToStatic)]
69pub struct IncludeFile<'i>(pub Cow<'i, str>);
70
71#[derive(Debug, PartialEq, Eq, ToStatic)]
73pub struct AccountDeclaration<'i> {
74 pub name: Cow<'i, str>,
76 pub details: Vec<AccountDetail<'i>>,
78}
79
80#[derive(Debug, PartialEq, Eq, ToStatic)]
82pub enum AccountDetail<'i> {
83 Comment(Cow<'i, str>),
85 Note(Cow<'i, str>),
88 Alias(Cow<'i, str>),
90}
91
92#[derive(Debug, PartialEq, Eq, ToStatic)]
94pub struct CommodityDeclaration<'i> {
95 pub name: Cow<'i, str>,
97 pub details: Vec<CommodityDetail<'i>>,
99}
100
101#[derive(Debug, PartialEq, Eq, ToStatic)]
103pub enum CommodityDetail<'i> {
104 Comment(Cow<'i, str>),
106 Note(Cow<'i, str>),
109 Alias(Cow<'i, str>),
112 Format(expr::Amount<'i>),
114}
115
116#[derive_where(Debug, PartialEq, Eq)]
118pub struct Transaction<'i, Deco: Decoration> {
119 pub date: NaiveDate,
121 pub effective_date: Option<NaiveDate>,
123 pub clear_state: ClearState,
125 pub code: Option<Cow<'i, str>>,
127 pub payee: Cow<'i, str>,
129 pub posts: Vec<Deco::Decorated<Posting<'i, Deco>>>,
131 pub metadata: Vec<Metadata<'i>>,
133}
134
135impl Transaction<'_, plain::Ident> {
136 #[cfg(test)]
137 fn to_static(&self) -> Transaction<'static, plain::Ident> {
138 let mut posts = Vec::new();
139 for p in &self.posts {
140 posts.push(p.to_static());
141 }
142 Transaction {
143 date: self.date,
144 effective_date: self.effective_date,
145 clear_state: self.clear_state,
146 code: self.code.to_static(),
147 payee: self.payee.to_static(),
148 posts,
149 metadata: self.metadata.to_static(),
150 }
151 }
152}
153
154impl<'i, Deco: Decoration> Transaction<'i, Deco> {
155 pub fn new<T>(date: NaiveDate, payee: T) -> Self
157 where
158 T: Into<Cow<'i, str>>,
159 {
160 Transaction {
161 date,
162 effective_date: None,
163 clear_state: ClearState::Uncleared,
164 code: None,
165 payee: payee.into(),
166 metadata: Vec::new(),
167 posts: Vec::new(),
168 }
169 }
170}
171
172#[derive_where(Debug, PartialEq, Eq)]
173pub struct Posting<'i, Deco: Decoration> {
175 pub account: Deco::Decorated<Cow<'i, str>>,
177 pub clear_state: ClearState,
179 pub amount: Option<PostingAmount<'i, Deco>>,
181 pub balance: Option<Deco::Decorated<expr::ValueExpr<'i>>>,
183 pub metadata: Vec<Metadata<'i>>,
185}
186
187impl Posting<'_, plain::Ident> {
188 #[cfg(test)]
189 fn to_static(&self) -> Posting<'static, plain::Ident> {
190 Posting {
191 account: self.account.to_static(),
192 clear_state: self.clear_state,
193 amount: self.amount.as_ref().map(|x| x.to_static()),
194 balance: self.balance.to_static(),
195 metadata: self.metadata.to_static(),
196 }
197 }
198}
199
200impl<'i> Posting<'i, plain::Ident> {
201 pub fn new_untracked<T>(account: T) -> Self
202 where
203 T: Into<Cow<'i, str>>,
204 {
205 Posting {
206 account: account.into(),
207 clear_state: ClearState::default(),
208 amount: None,
209 balance: None,
210 metadata: Vec::new(),
211 }
212 }
213}
214
215impl<'i, Deco: Decoration> Posting<'i, Deco> {
216 pub fn new(account: Deco::Decorated<Cow<'i, str>>) -> Self {
217 Posting {
218 account,
219 clear_state: ClearState::default(),
220 amount: None,
221 balance: None,
222 metadata: Vec::new(),
223 }
224 }
225}
226
227#[derive(Debug, PartialEq, Eq, Clone, Copy, Default, ToStatic)]
229pub enum ClearState {
230 #[default]
232 Uncleared,
233 Cleared,
235 Pending,
237}
238
239#[derive(Debug, PartialEq, Eq, ToStatic)]
241pub enum Metadata<'i> {
242 Comment(Cow<'i, str>),
244 WordTags(Vec<Cow<'i, str>>),
246 KeyValueTag {
248 key: Cow<'i, str>,
249 value: MetadataValue<'i>,
250 },
251}
252
253#[derive(Debug, PartialEq, Eq, ToStatic)]
255pub enum MetadataValue<'i> {
256 Text(Cow<'i, str>),
258 Expr(Cow<'i, str>),
261}
262
263#[derive_where(Debug, PartialEq, Eq)]
269pub struct PostingAmount<'i, Deco: Decoration> {
270 pub amount: Deco::Decorated<expr::ValueExpr<'i>>,
271 pub cost: Option<Deco::Decorated<Exchange<'i>>>,
272 pub lot: Lot<'i, Deco>,
273}
274
275impl PostingAmount<'_, plain::Ident> {
276 #[cfg(test)]
277 fn to_static(&self) -> PostingAmount<'static, plain::Ident> {
278 PostingAmount {
279 amount: self.amount.to_static(),
280 cost: self.cost.to_static(),
281 lot: self.lot.to_static(),
282 }
283 }
284}
285
286impl<'i> From<expr::ValueExpr<'i>> for PostingAmount<'i, plain::Ident> {
287 fn from(v: expr::ValueExpr<'i>) -> Self {
288 PostingAmount {
289 amount: v,
290 cost: None,
291 lot: Lot::default(),
292 }
293 }
294}
295
296#[derive_where(Debug, PartialEq, Eq)]
298pub struct Lot<'i, Deco: Decoration> {
299 pub price: Option<Deco::Decorated<Exchange<'i>>>,
300 pub date: Option<NaiveDate>,
301 pub note: Option<Cow<'i, str>>,
302}
303
304impl Lot<'_, plain::Ident> {
305 #[cfg(test)]
306 fn to_static(&self) -> Lot<'static, plain::Ident> {
307 Lot {
308 price: self.price.to_static(),
309 date: self.date.to_static(),
310 note: self.note.to_static(),
311 }
312 }
313}
314
315impl<Deco: Decoration> Default for Lot<'_, Deco> {
316 fn default() -> Self {
317 Self {
318 price: None,
319 date: None,
320 note: None,
321 }
322 }
323}
324
325#[derive(Debug, PartialEq, Eq, ToStatic)]
327pub enum Exchange<'i> {
328 Total(expr::ValueExpr<'i>),
333 Rate(expr::ValueExpr<'i>),
338}
339
340#[derive(Debug, PartialEq, Eq, ToStatic)]
343pub struct PriceDBEntry<'i> {
344 pub datetime: NaiveDateTime,
345 pub target: Cow<'i, str>,
347 pub rate: expr::Amount<'i>,
350}