use rust_decimal::Decimal;
use serde::{Deserialize, Serialize};
use std::{
borrow::Cow,
collections::{HashMap, HashSet},
};
use strum_macros;
use time::Date;
use super::iso8601date;
#[derive(Serialize, Deserialize, PartialEq, Eq, Clone, Debug)]
#[serde(rename_all = "kebab-case")]
pub struct Directive<'a> {
#[serde(skip_serializing_if = "Option::is_none")]
pub(crate) span: Option<Span>,
#[serde(with = "iso8601date")]
pub(crate) date: Date,
#[serde(skip_serializing_if = "Option::is_none")]
pub(crate) tags: Option<HashSet<&'a str>>,
#[serde(skip_serializing_if = "Option::is_none")]
pub(crate) links: Option<HashSet<&'a str>>,
#[serde(skip_serializing_if = "Option::is_none")]
pub(crate) metadata: Option<HashMap<&'a str, MetaValue<'a>>>,
#[serde(borrow)]
#[serde(flatten)]
pub(crate) variant: DirectiveVariant<'a>,
}
#[derive(Serialize, Deserialize, PartialEq, Eq, strum_macros::IntoStaticStr, Clone, Debug)]
#[serde(rename_all = "kebab-case")]
#[serde(tag = "dct")]
#[strum(serialize_all = "kebab-case")]
pub enum DirectiveVariant<'a> {
#[serde(rename = "txn")]
Transaction(Transaction<'a>),
Price(PriceDct<'a>),
Balance(Balance<'a>),
#[serde(borrow)]
Open(Open<'a>),
Close(Close<'a>),
Commodity(Commodity<'a>),
Pad(Pad<'a>),
Document(Document<'a>),
Note(Note<'a>),
Event(Event<'a>),
Query(Query<'a>),
Custom(Custom<'a>),
}
#[derive(Serialize, Deserialize, PartialEq, Eq, Clone, Debug)]
#[serde(rename_all = "kebab-case")]
pub struct Transaction<'a> {
pub(crate) flag: Cow<'static, str>,
#[serde(skip_serializing_if = "Option::is_none")]
pub(crate) payee: Option<Cow<'a, str>>,
#[serde(skip_serializing_if = "Option::is_none")]
pub(crate) narration: Option<Cow<'a, str>>,
#[serde(borrow)]
pub(crate) postings: Vec<PostingSpec<'a>>,
}
#[derive(Serialize, Deserialize, PartialEq, Eq, Clone, Debug)]
#[serde(rename_all = "kebab-case")]
pub struct PriceDct<'a> {
pub(crate) cur: &'a str,
pub(crate) price: Price<'a>,
}
#[derive(Serialize, Deserialize, PartialEq, Eq, Clone, Debug)]
#[serde(rename_all = "kebab-case")]
pub struct Balance<'a> {
pub(crate) acc: &'a str,
pub(crate) units: Decimal,
pub(crate) cur: &'a str,
#[serde(skip_serializing_if = "Option::is_none")]
pub(crate) tolerance: Option<Decimal>,
}
#[derive(Serialize, Deserialize, PartialEq, Eq, Clone, Debug)]
#[serde(rename_all = "kebab-case")]
pub struct Open<'a> {
pub(crate) acc: &'a str,
#[serde(skip_serializing_if = "Option::is_none")]
pub(crate) currencies: Option<HashSet<&'a str>>,
#[serde(skip_serializing_if = "Option::is_none")]
pub(crate) booking: Option<Booking>,
}
#[derive(Serialize, Deserialize, PartialEq, Eq, Clone, Debug)]
#[serde(rename_all = "kebab-case")]
pub struct Close<'a> {
pub(crate) acc: &'a str,
}
#[derive(Serialize, Deserialize, PartialEq, Eq, Clone, Debug)]
#[serde(rename_all = "kebab-case")]
pub struct Commodity<'a> {
pub(crate) cur: &'a str,
}
#[derive(Serialize, Deserialize, PartialEq, Eq, Clone, Debug)]
#[serde(rename_all = "kebab-case")]
pub struct Pad<'a> {
pub(crate) acc: &'a str,
pub(crate) source: &'a str,
}
#[derive(Serialize, Deserialize, PartialEq, Eq, Clone, Debug)]
#[serde(rename_all = "kebab-case")]
pub struct Document<'a> {
pub(crate) acc: &'a str,
pub(crate) path: Cow<'a, str>,
}
#[derive(Serialize, Deserialize, PartialEq, Eq, Clone, Debug)]
#[serde(rename_all = "kebab-case")]
pub struct Note<'a> {
pub(crate) acc: &'a str,
pub(crate) comment: Cow<'a, str>,
}
#[derive(Serialize, Deserialize, PartialEq, Eq, Clone, Debug)]
#[serde(rename_all = "kebab-case")]
pub struct Event<'a> {
#[serde(rename = "type")]
pub(crate) type_: Cow<'a, str>,
pub(crate) description: Cow<'a, str>,
}
#[derive(Serialize, Deserialize, PartialEq, Eq, Clone, Debug)]
#[serde(rename_all = "kebab-case")]
pub struct Query<'a> {
pub(crate) name: Cow<'a, str>,
pub(crate) content: Cow<'a, str>,
}
#[derive(Serialize, Deserialize, PartialEq, Eq, Clone, Debug)]
#[serde(rename_all = "kebab-case")]
pub struct Custom<'a> {
#[serde(rename = "type")]
pub(crate) type_: Cow<'a, str>,
#[serde(borrow)]
pub(crate) values: Vec<MetaValue<'a>>,
}
#[derive(Serialize, Deserialize, PartialEq, Eq, Clone, Debug)]
#[serde(rename_all = "kebab-case")]
pub struct PostingSpec<'a> {
#[serde(skip_serializing_if = "Option::is_none")]
pub(crate) span: Option<Span>,
#[serde(skip_serializing_if = "Option::is_none")]
pub(crate) flag: Option<Cow<'static, str>>,
pub(crate) acc: &'a str,
#[serde(skip_serializing_if = "Option::is_none")]
pub(crate) units: Option<Decimal>,
#[serde(skip_serializing_if = "Option::is_none")]
pub(crate) cur: Option<&'a str>,
#[serde(skip_serializing_if = "Option::is_none")]
pub(crate) cost_spec: Option<CostSpec<'a>>,
#[serde(skip_serializing_if = "Option::is_none")]
pub(crate) price_spec: Option<PriceSpec<'a>>,
#[serde(skip_serializing_if = "Option::is_none")]
pub(crate) tags: Option<HashSet<&'a str>>,
#[serde(skip_serializing_if = "Option::is_none")]
pub(crate) links: Option<HashSet<&'a str>>,
#[serde(skip_serializing_if = "Option::is_none")]
pub(crate) metadata: Option<HashMap<&'a str, MetaValue<'a>>>,
}
#[derive(Serialize, Deserialize, PartialEq, Eq, Default, Clone, Debug)]
#[serde(rename_all = "kebab-case")]
pub struct CostSpec<'a> {
#[serde(skip_serializing_if = "Option::is_none")]
pub(crate) per_unit: Option<Decimal>,
#[serde(skip_serializing_if = "Option::is_none")]
pub(crate) total: Option<Decimal>,
#[serde(skip_serializing_if = "Option::is_none")]
pub(crate) cur: Option<&'a str>,
#[serde(skip_serializing_if = "Option::is_none")]
#[serde(with = "iso8601date::option")]
#[serde(default)]
pub(crate) date: Option<Date>,
#[serde(skip_serializing_if = "Option::is_none")]
pub(crate) label: Option<Cow<'a, str>>,
#[serde(skip_serializing_if = "std::ops::Not::not")]
#[serde(default)]
pub(crate) merge: bool,
}
#[derive(Serialize, Deserialize, PartialEq, Eq, Default, Clone, Debug)]
#[serde(rename_all = "kebab-case")]
pub struct PriceSpec<'a> {
#[serde(skip_serializing_if = "Option::is_none")]
pub(crate) per_unit: Option<Decimal>,
#[serde(skip_serializing_if = "Option::is_none")]
pub(crate) total: Option<Decimal>,
#[serde(skip_serializing_if = "Option::is_none")]
pub(crate) cur: Option<&'a str>,
}
#[derive(Serialize, Deserialize, PartialEq, Eq, Clone, Debug)]
#[serde(rename_all = "kebab-case")]
pub struct Price<'a> {
pub(crate) per_unit: Decimal,
#[serde(skip_serializing_if = "Option::is_none")]
pub(crate) total: Option<Decimal>,
pub(crate) cur: &'a str,
}
#[derive(PartialEq, Eq, Clone, Debug)]
pub enum MetaValue<'a> {
Amount(Decimal, &'a str), String(Cow<'a, str>),
Currency(&'a str),
Account(&'a str),
Tag(&'a str),
Link(&'a str),
Date(Date),
Bool(bool),
Number(Decimal),
Null,
}
#[derive(Serialize, Clone, Debug)]
#[serde(rename_all = "kebab-case")]
pub struct Options<'a> {
pub(crate) name_assets: &'a str,
pub(crate) name_liabilities: &'a str,
pub(crate) name_equity: &'a str,
pub(crate) name_income: &'a str,
pub(crate) name_expenses: &'a str,
#[serde(skip_serializing_if = "Option::is_none")]
pub(crate) title: Option<&'a str>,
#[serde(skip_serializing_if = "Option::is_none")]
pub(crate) account_previous_balances: Option<&'a str>,
#[serde(skip_serializing_if = "Option::is_none")]
pub(crate) account_previous_earnings: Option<&'a str>,
#[serde(skip_serializing_if = "Option::is_none")]
pub(crate) account_previous_conversions: Option<&'a str>,
#[serde(skip_serializing_if = "Option::is_none")]
pub(crate) account_current_earnings: Option<&'a str>,
#[serde(skip_serializing_if = "Option::is_none")]
pub(crate) account_current_conversions: Option<&'a str>,
#[serde(skip_serializing_if = "Option::is_none")]
pub(crate) account_unrealized_gains: Option<&'a str>,
#[serde(skip_serializing_if = "Option::is_none")]
pub(crate) account_rounding: Option<&'a str>,
#[serde(skip_serializing_if = "Option::is_none")]
pub(crate) conversion_currency: Option<&'a str>,
#[serde(skip_serializing_if = "Option::is_none")]
pub(crate) inferred_tolerance_default: Option<HashMap<&'a str, Decimal>>,
#[serde(skip_serializing_if = "Option::is_none")]
pub(crate) inferred_tolerance_default_fallback: Option<Decimal>,
#[serde(skip_serializing_if = "Option::is_none")]
pub(crate) inferred_tolerance_multiplier: Option<Decimal>,
#[serde(skip_serializing_if = "Option::is_none")]
pub(crate) infer_tolerance_from_cost: Option<bool>,
#[serde(skip_serializing_if = "Option::is_none")]
pub(crate) documents: Option<HashSet<String>>,
#[serde(skip_serializing_if = "Option::is_none")]
pub(crate) operating_currency: Option<HashSet<&'a str>>,
#[serde(skip_serializing_if = "Option::is_none")]
pub(crate) render_commas: Option<bool>,
#[serde(skip_serializing_if = "Option::is_none")]
pub(crate) booking_method: Option<Booking>,
#[serde(skip_serializing_if = "Option::is_none")]
pub(crate) plugin_processing_mode: Option<PluginProcessingMode>,
}
#[derive(Serialize, Deserialize, PartialEq, Eq, Clone, Copy, Debug)]
#[serde(rename_all = "kebab-case")]
pub enum Booking {
Strict,
StrictWithSize,
None,
Average,
Fifo,
Lifo,
Hifo,
}
#[derive(Serialize, Deserialize, PartialEq, Eq, Clone, Copy, Debug)]
#[serde(rename_all = "kebab-case")]
pub enum PluginProcessingMode {
Default,
Raw,
}
#[derive(Serialize, PartialEq, Eq, Clone, Debug)]
#[serde(rename_all = "kebab-case")]
pub struct SpannedSource<'a> {
#[serde(skip_serializing_if = "Option::is_none")]
pub file_name: Option<&'a str>,
pub start_line: usize,
pub end_line: usize,
pub content: &'a str,
}
#[derive(PartialEq, Eq, Copy, Clone, Debug)]
pub(crate) struct Span {
pub(crate) source: usize,
pub(crate) start: usize,
pub(crate) end: usize,
}