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;
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<'i> LedgerEntry<'i, 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<'i> Transaction<'i, 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: 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<'i> Posting<'i, 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, Deco: Decoration> Posting<'i, Deco> {
201 pub fn new<T: Into<Cow<'i, str>>>(account: T) -> Self {
202 Posting {
203 account: account.into(),
204 clear_state: ClearState::default(),
205 amount: None,
206 balance: None,
207 metadata: Vec::new(),
208 }
209 }
210}
211
212#[derive(Debug, PartialEq, Eq, Clone, Copy, Default, ToStatic)]
214pub enum ClearState {
215 #[default]
217 Uncleared,
218 Cleared,
220 Pending,
222}
223
224#[derive(Debug, PartialEq, Eq, ToStatic)]
226pub enum Metadata<'i> {
227 Comment(Cow<'i, str>),
229 WordTags(Vec<Cow<'i, str>>),
231 KeyValueTag {
233 key: Cow<'i, str>,
234 value: MetadataValue<'i>,
235 },
236}
237
238#[derive(Debug, PartialEq, Eq, ToStatic)]
240pub enum MetadataValue<'i> {
241 Text(Cow<'i, str>),
243 Expr(Cow<'i, str>),
246}
247
248#[derive_where(Debug, PartialEq, Eq)]
254pub struct PostingAmount<'i, Deco: Decoration> {
255 pub amount: Deco::Decorated<expr::ValueExpr<'i>>,
256 pub cost: Option<Deco::Decorated<Exchange<'i>>>,
257 pub lot: Lot<'i, Deco>,
258}
259
260impl<'i> PostingAmount<'i, plain::Ident> {
261 #[cfg(test)]
262 fn to_static(&self) -> PostingAmount<'static, plain::Ident> {
263 PostingAmount {
264 amount: self.amount.to_static(),
265 cost: self.cost.to_static(),
266 lot: self.lot.to_static(),
267 }
268 }
269}
270
271impl<'i> From<expr::ValueExpr<'i>> for PostingAmount<'i, plain::Ident> {
272 fn from(v: expr::ValueExpr<'i>) -> Self {
273 PostingAmount {
274 amount: v,
275 cost: None,
276 lot: Lot::default(),
277 }
278 }
279}
280
281#[derive_where(Debug, PartialEq, Eq)]
283pub struct Lot<'i, Deco: Decoration> {
284 pub price: Option<Deco::Decorated<Exchange<'i>>>,
285 pub date: Option<NaiveDate>,
286 pub note: Option<Cow<'i, str>>,
287}
288
289impl<'i> Lot<'i, plain::Ident> {
290 #[cfg(test)]
291 fn to_static(&self) -> Lot<'static, plain::Ident> {
292 Lot {
293 price: self.price.to_static(),
294 date: self.date.to_static(),
295 note: self.note.to_static(),
296 }
297 }
298}
299
300impl<'i, Deco: Decoration> Default for Lot<'i, Deco> {
301 fn default() -> Self {
302 Self {
303 price: None,
304 date: None,
305 note: None,
306 }
307 }
308}
309
310#[derive(Debug, PartialEq, Eq, ToStatic)]
312pub enum Exchange<'i> {
313 Total(expr::ValueExpr<'i>),
318 Rate(expr::ValueExpr<'i>),
323}