YDK6X6PPD42DMLFGF6OO2O3G7GA4Z2PCIDJIREHX6XNX2NYEBJSQC use crate::Account;use crate::Amount;use crate::CostBasis;use std::fmt::Display;use std::fmt::Write as _;use std::hash::Hash;use time::Date;#[derive(Clone, Debug, Eq, Hash, PartialEq)]pub struct Posting {pub flag: Option<TransactionFlag>,pub account: Account,pub amount: Option<Amount>,pub cost: Option<CostBasis>,pub price: Option<Amount>,}impl Display for Posting {fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {let Posting {flag,account,amount,cost,price,} = self;if let Some(flag) = flag {write!(f, "{flag} ")?;}write!(f, "{account}")?;if let Some(amount) = amount {write!(f, " {amount}")?;if let Some(cost) = cost {write!(f, " {cost}")?;}if let Some(price) = price {write!(f, " @ {price}")?;}}Ok(())}}#[derive(Clone, Debug, Eq, Hash, PartialEq)]pub struct Transaction {pub date: Date,pub flag: TransactionFlag,pub payee: Option<String>,pub narration: Option<String>,pub postings: Vec<Posting>,}impl Display for Transaction {fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {let Self {date,flag,payee,narration,postings,} = self;write!(f, "{date} {flag}")?;match (payee, narration) {(None, None) => {}(None, Some(narration)) => write!(f, r#" "{narration}""#)?,(Some(payee), None) => write!(f, r#" "{payee}" """#)?,(Some(payee), Some(narration)) => write!(f, r#" "{payee}" "{narration}""#)?,}for posting in postings {write!(f, "\n {posting}")?;}Ok(())}}#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]pub enum TransactionFlag {Complete,Incomplete,}impl Display for TransactionFlag {fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {f.write_char(match self {TransactionFlag::Complete => '*',TransactionFlag::Incomplete => '!',})}}
mod account {use crate::account::Acc;use crate::account::Account;use static_assertions::assert_impl_all;use std::fmt::Debug;use std::hash::Hash;use std::str::FromStr;use test_case::test_case;assert_impl_all!(Account: Clone,Debug,FromStr,Hash,Ord,TryFrom<&'static str>);#[test_case("Assets"; "only top-level")]#[test_case("Equity:OpeningBalances"; "subaccount")]#[test_case("Expenses:Banking-Fees"; "subaccount with dash")]#[test_case("Income:Sales:2022"; "subaccount starting with number")]#[test_case("Liabilities:Credit-Cards:VISA"; "multiple levels")]fn parse_when_valid(name: &str) {let acc = <&Acc>::try_from(name).unwrap();let account = Account::try_from(name).unwrap();assert_eq!(account, name);assert_eq!(acc, name);}#[test_case("Cash"; "invalid account type")]#[test_case("Assets:Accounts_Receivable"; "invalid characters")]#[test_case("Assets:-Test"; "subaccount starting with dash")]#[test_case("Income::Sales"; "empty segment")]fn do_not_parse_when_invalid(name: &str) {<&Acc>::try_from(name).unwrap_err();}}mod amount {use {crate::Amount,static_assertions::assert_impl_all,std::{fmt::Debug, hash::Hash, str::FromStr},test_case::test_case,};assert_impl_all!(Amount: Copy,Debug,FromStr,Hash,PartialOrd,TryFrom<&'static str>);#[test_case("0 EUR"; "zero")]#[test_case("15 USD"; "integer amount")]#[test_case("0.30 CAD"; "fractional amount")]#[test_case("0.0000067 ETH"; "arbitrary precision")]#[test_case("-16.93 USD"; "negative amount")]fn parse_when_valid(amount: &str) {let account = Amount::try_from(amount).unwrap();assert_eq!(account.to_string(), amount);}#[test_case(" EUR"; "missing units")]#[test_case("15 "; "missing commodity")]#[test_case("15,000.00 USD"; "thousands separator")]#[test_case("15000,00 USD"; "invalid decimal separator")]fn do_not_parse_when_invalid(amount: &str) {Amount::try_from(amount).unwrap_err();}}mod commodities {use {crate::Commodity,static_assertions::assert_impl_all,std::{fmt::Debug, hash::Hash, str::FromStr},test_case::test_case,};assert_impl_all!(Commodity: Copy,Debug,FromStr,Hash,Ord,TryFrom<&'static str>);#[test_case("A"; "single letter")]#[test_case("USD"; "dollar")]#[test_case("EUR"; "euro")]#[test_case("MSFT"; "stock")]#[test_case("AIRMILE"; "creative")]#[test_case("DE.-_3"; "with special characters")]fn parse_when_valid(name: &str) {let commodity = Commodity::try_from(name).unwrap();assert_eq!(commodity.to_string(), name);}#[test_case("0"; "starting with number")]#[test_case("D-"; "ending with dash")]#[test_case("E_"; "ending with underscore")]#[test_case("X."; "ending with dot")]#[test_case("X 3"; "containing space")]#[test_case("X\\0"; "containing backslash")]fn do_not_parse_when_invalid(name: &str) {Commodity::try_from(name).unwrap_err();}// TODO proptest?}
use std::fmt::Display;use time::Date;mod account;mod amount;mod balance;mod commodity;mod cost;mod transaction;pub use crate::account::Acc;pub use crate::account::Account;pub use crate::amount::Amount;pub use crate::balance::Balance;pub use crate::commodity::Commodity;pub use crate::cost::CostBasis;pub use crate::transaction::Posting;pub use crate::transaction::Transaction;pub use crate::transaction::TransactionFlag;#[derive(Clone, Debug)]pub enum Directive {Balance(balance::Balance),Transaction(transaction::Transaction),}impl Directive {pub fn date(&self) -> Date {match self {Self::Balance(balance) => balance.date,Self::Transaction(transaction) => transaction.date,}}pub fn main_account(&self) -> Option<&Acc> {match self {Directive::Balance(balance) => Some(&balance.account),Directive::Transaction(transaction) => transaction.postings.get(0).map(|posting| posting.account.as_ref()),}}}impl Display for Directive {fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {match self {Self::Balance(balance) => balance.fmt(f),Self::Transaction(transaction) => transaction.fmt(f),}}}impl From<balance::Balance> for Directive {fn from(balance: balance::Balance) -> Self {Self::Balance(balance)}}impl From<transaction::Transaction> for Directive {fn from(transaction: transaction::Transaction) -> Self {Self::Transaction(transaction)}}#[cfg(test)]mod that;
use crate::amount::Amount;use std::fmt::Display;use std::hash::Hash;#[derive(Clone, Debug, Eq, Hash, PartialEq)]pub enum CostBasis {Empty,PerUnit(Amount),Total(Amount),}impl Display for CostBasis {fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {match self {Self::Empty => write!(f, "{{}}"),Self::PerUnit(amount) => write!(f, "{{{amount}}}"),Self::Total(amount) => write!(f, "{{{{{amount}}}}}"),}}}
use arrayvec::ArrayString;use snafu::ensure;use snafu::Backtrace;use snafu::Snafu;use std::fmt::Display;use std::str::FromStr;#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]pub struct Commodity {pub(crate) name: ArrayString<24>,}impl Display for Commodity {fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {f.pad(&self.name)}}impl FromStr for Commodity {type Err = <Self as TryFrom<&'static str>>::Error;fn from_str(name: &str) -> Result<Self, Self::Err> {Self::try_from(name)}}impl TryFrom<&str> for Commodity {type Error = CommodityError;fn try_from(name: &str) -> Result<Self, Self::Error> {ensure!(lazy_regex::regex_is_match!("^[A-Z](?:[-A-Z0-9._]{0,22}[A-Z0-9])?$", name),CommoditySnafu { name });let name = name.try_into().expect("length should fit");Ok(Self { name })}}#[derive(Debug, Snafu)]#[snafu(display("invalid commodity: {name:?}"))]pub struct CommodityError {pub(crate) name: String,pub(crate) backtrace: Backtrace,}
use crate::Account;use crate::Amount;use std::fmt::Display;use std::hash::Hash;use time::Date;#[derive(Clone, Debug, Eq, Hash, PartialEq)]pub struct Balance {pub date: Date,pub account: Account,pub amount: Amount,}impl Display for Balance {fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {let Balance {date,account,amount,} = self;write!(f, "{date} balance {account} {amount}")}}
use crate::Commodity;use rust_decimal::Decimal;use snafu::Backtrace;use snafu::OptionExt as _;use snafu::Snafu;use std::fmt::Display;use std::ops::Neg;use std::str::FromStr;#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]pub struct Amount {pub amount: Decimal,pub commodity: Commodity,}impl Display for Amount {fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {let Self { amount, commodity } = self;write!(f, "{amount} {commodity}")}}impl FromStr for Amount {type Err = <Self as TryFrom<&'static str>>::Error;fn from_str(amount: &str) -> Result<Self, Self::Err> {Self::try_from(amount)}}impl Neg for Amount {type Output = Self;fn neg(self) -> Self::Output {Self {amount: -self.amount,..self}}}impl PartialOrd for Amount {fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {(self.commodity == other.commodity).then(|| self.amount.cmp(&other.amount))}}impl TryFrom<&str> for Amount {type Error = AmountError;fn try_from(amount: &str) -> Result<Self, Self::Error> {let context = AmountSnafu { value: amount };let (amount, commodity) = amount.split_once(' ').context(context)?;let amount = amount.parse().map_err(|_| context.build())?;let commodity = commodity.parse().map_err(|_| context.build())?;Ok(Self { amount, commodity })}}#[derive(Debug, Snafu)]pub struct AmountError {value: String,backtrace: Backtrace,}
use delegate::delegate;use snafu::ensure;use snafu::Backtrace;use snafu::Snafu;use std::borrow::Borrow;use std::borrow::Cow;use std::cmp::Ordering;use std::fmt::Display;use std::hash::Hash;use std::iter::FusedIterator;use std::ops::Deref;use std::str::FromStr;use std::str::Split;#[derive(Debug)]#[repr(transparent)]pub struct Acc {name: str,}impl Acc {pub fn ancestors(&self) -> impl Iterator<Item = &Self> + '_ {Ancestors { next: Some(self) }}pub fn segments(&self) -> Segments<'_> {Segments {inner: self.name.split(':'),}}pub fn parent(&self) -> Option<&Self> {self.name.split_once(':').map(|(parent, _)| unsafe { Self::from_unchecked(parent) })}const unsafe fn from_unchecked(name: &str) -> &Self {&*(name as *const _ as *const _)}}impl AsRef<str> for Acc {#[inline]fn as_ref(&self) -> &str {self.borrow()}}impl Borrow<str> for Acc {#[inline]fn borrow(&self) -> &str {&self.name}}impl Display for Acc {#[inline]fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {f.pad(&self.name)}}impl Eq for Acc {}impl Hash for Acc {#[inline]fn hash<H>(&self, state: &mut H)whereH: std::hash::Hasher,{self.name.hash(state);}}impl Ord for Acc {#[inline]fn cmp(&self, other: &Self) -> Ordering {self.segments().cmp(other.segments())}}impl PartialEq for Acc {#[inline]fn eq(&self, other: &Self) -> bool {self.cmp(other).is_eq()}}impl PartialEq<&str> for Acc {#[inline]fn eq(&self, other: &&str) -> bool {self.partial_cmp(other).map_or(false, Ordering::is_eq)}}impl PartialEq<Acc> for &str {#[inline]fn eq(&self, other: &Acc) -> bool {self.partial_cmp(other).map_or(false, Ordering::is_eq)}}impl PartialEq<Acc> for Cow<'_, Acc> {#[inline]fn eq(&self, other: &Acc) -> bool {self.partial_cmp(other).map_or(false, Ordering::is_eq)}}impl PartialEq<Acc> for Cow<'_, str> {#[inline]fn eq(&self, other: &Acc) -> bool {self.partial_cmp(other).map_or(false, Ordering::is_eq)}}impl PartialEq<Acc> for String {#[inline]fn eq(&self, other: &Acc) -> bool {self.partial_cmp(other).map_or(false, Ordering::is_eq)}}impl PartialEq<Acc> for str {#[inline]fn eq(&self, other: &Acc) -> bool {self.partial_cmp(other).map_or(false, Ordering::is_eq)}}impl PartialEq<Cow<'_, Self>> for Acc {#[inline]fn eq(&self, other: &Cow<'_, Self>) -> bool {self.partial_cmp(other).map_or(false, Ordering::is_eq)}}impl PartialEq<Cow<'_, str>> for Acc {#[inline]fn eq(&self, other: &Cow<'_, str>) -> bool {self.partial_cmp(other).map_or(false, Ordering::is_eq)}}impl PartialEq<String> for Acc {#[inline]fn eq(&self, other: &String) -> bool {self.partial_cmp(other).map_or(false, Ordering::is_eq)}}impl PartialEq<str> for Acc {#[inline]fn eq(&self, other: &str) -> bool {self.partial_cmp(other).map_or(false, Ordering::is_eq)}}impl PartialOrd for Acc {#[inline]fn partial_cmp(&self, other: &Self) -> Option<Ordering> {Some(self.cmp(other))}}impl PartialOrd<&str> for Acc {#[inline]fn partial_cmp(&self, other: &&str) -> Option<Ordering> {self.partial_cmp(*other)}}impl PartialOrd<Acc> for &str {#[inline]fn partial_cmp(&self, other: &Acc) -> Option<Ordering> {other.partial_cmp(self).map(Ordering::reverse)}}impl PartialOrd<Acc> for Cow<'_, Acc> {#[inline]fn partial_cmp(&self, other: &Acc) -> Option<Ordering> {other.partial_cmp(self).map(Ordering::reverse)}}impl PartialOrd<Acc> for Cow<'_, str> {#[inline]fn partial_cmp(&self, other: &Acc) -> Option<Ordering> {other.partial_cmp(self).map(Ordering::reverse)}}impl PartialOrd<Acc> for String {#[inline]fn partial_cmp(&self, other: &Acc) -> Option<Ordering> {other.partial_cmp(self).map(Ordering::reverse)}}impl PartialOrd<Acc> for str {#[inline]fn partial_cmp(&self, other: &Acc) -> Option<Ordering> {other.partial_cmp(self).map(Ordering::reverse)}}impl PartialOrd<Cow<'_, Acc>> for Acc {fn partial_cmp(&self, other: &Cow<'_, Acc>) -> Option<Ordering> {self.partial_cmp(&**other)}}impl PartialOrd<Cow<'_, str>> for Acc {fn partial_cmp(&self, other: &Cow<'_, str>) -> Option<Ordering> {self.partial_cmp(&**other)}}impl PartialOrd<String> for Acc {#[inline]fn partial_cmp(&self, other: &String) -> Option<Ordering> {self.partial_cmp(&**other)}}impl PartialOrd<str> for Acc {#[inline]fn partial_cmp(&self, other: &str) -> Option<Ordering> {other.try_into().ok().map(|other| self.cmp(other))}}impl ToOwned for Acc {type Owned = Account;fn to_owned(&self) -> Self::Owned {Account {name: self.name.to_owned(),}}}impl<'a> TryFrom<&'a str> for &'a Acc {type Error = AccountError;fn try_from(name: &'a str) -> Result<Self, Self::Error> {ensure!(is_valid_account_name(name), AccountSnafu { name });Ok(unsafe { Acc::from_unchecked(name) })}}#[derive(Clone, Debug)]#[repr(transparent)]pub struct Account {name: String,}impl Account {pub fn join(self, segment: impl AsRef<str>) -> Result<Self, AccountError> {fn join_inner(mut this: Account, segment: &str) -> Result<Account, AccountError> {ensure!(is_valid_account_segment(segment),AccountSnafu { name: segment });this.name.push(':');this.name.push_str(segment);Ok(this)}join_inner(self, segment.as_ref())}}impl AsRef<Acc> for Account {#[inline]fn as_ref(&self) -> &Acc {self}}impl AsRef<String> for Account {#[inline]fn as_ref(&self) -> &String {self.borrow()}}impl AsRef<str> for Account {#[inline]fn as_ref(&self) -> &str {self.borrow()}}impl Borrow<Acc> for Account {#[inline]fn borrow(&self) -> &Acc {self}}impl Borrow<String> for Account {#[inline]fn borrow(&self) -> &String {&self.name}}impl Borrow<str> for Account {#[inline]fn borrow(&self) -> &str {&self.name}}impl Deref for Account {type Target = Acc;#[inline]fn deref(&self) -> &Self::Target {unsafe { Acc::from_unchecked(&self.name) }}}impl Display for Account {#[inline]fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {(**self).fmt(f)}}impl Eq for Account {}impl From<&Acc> for Account {#[inline]fn from(acc: &Acc) -> Self {acc.to_owned()}}impl FromStr for Account {type Err = <Self as TryFrom<&'static str>>::Error;#[inline]fn from_str(name: &str) -> Result<Self, Self::Err> {Self::try_from(name)}}impl Hash for Account {#[inline]fn hash<H: std::hash::Hasher>(&self, state: &mut H) {(**self).hash(state)}}impl Ord for Account {#[inline]fn cmp(&self, other: &Self) -> Ordering {(**self).cmp(&**other)}}impl PartialEq for Account {#[inline]fn eq(&self, other: &Self) -> bool {self.cmp(other).is_eq()}}impl PartialEq<&Acc> for Account {#[inline]fn eq(&self, other: &&Acc) -> bool {self.partial_cmp(other).map_or(false, Ordering::is_eq)}}impl PartialEq<&str> for Account {#[inline]fn eq(&self, other: &&str) -> bool {self.partial_cmp(other).map_or(false, Ordering::is_eq)}}impl PartialEq<Acc> for Account {#[inline]fn eq(&self, other: &Acc) -> bool {self.partial_cmp(other).map_or(false, Ordering::is_eq)}}impl PartialEq<Account> for &Acc {#[inline]fn eq(&self, other: &Account) -> bool {self.partial_cmp(other).map_or(false, Ordering::is_eq)}}impl PartialEq<Account> for &str {#[inline]fn eq(&self, other: &Account) -> bool {self.partial_cmp(other).map_or(false, Ordering::is_eq)}}impl PartialEq<Account> for Acc {#[inline]fn eq(&self, other: &Account) -> bool {self.partial_cmp(other).map_or(false, Ordering::is_eq)}}impl PartialEq<Account> for Cow<'_, Acc> {#[inline]fn eq(&self, other: &Account) -> bool {self.partial_cmp(other).map_or(false, Ordering::is_eq)}}impl PartialEq<Account> for Cow<'_, str> {#[inline]fn eq(&self, other: &Account) -> bool {self.partial_cmp(other).map_or(false, Ordering::is_eq)}}impl PartialEq<Account> for String {#[inline]fn eq(&self, other: &Account) -> bool {self.partial_cmp(other).map_or(false, Ordering::is_eq)}}impl PartialEq<Account> for str {#[inline]fn eq(&self, other: &Account) -> bool {self.partial_cmp(other).map_or(false, Ordering::is_eq)}}impl PartialEq<Cow<'_, Acc>> for Account {#[inline]fn eq(&self, other: &Cow<'_, Acc>) -> bool {self.partial_cmp(other).map_or(false, Ordering::is_eq)}}impl PartialEq<Cow<'_, str>> for Account {#[inline]fn eq(&self, other: &Cow<'_, str>) -> bool {self.partial_cmp(other).map_or(false, Ordering::is_eq)}}impl PartialEq<String> for Account {#[inline]fn eq(&self, other: &String) -> bool {self.partial_cmp(other).map_or(false, Ordering::is_eq)}}impl PartialEq<str> for Account {#[inline]fn eq(&self, other: &str) -> bool {self.partial_cmp(other).map_or(false, Ordering::is_eq)}}impl PartialOrd for Account {#[inline]fn partial_cmp(&self, other: &Self) -> Option<Ordering> {Some(self.cmp(other))}}impl PartialOrd<&Acc> for Account {#[inline]fn partial_cmp(&self, other: &&Acc) -> Option<Ordering> {self.partial_cmp(*other)}}impl PartialOrd<&str> for Account {#[inline]fn partial_cmp(&self, other: &&str) -> Option<Ordering> {self.partial_cmp(*other)}}impl PartialOrd<Acc> for Account {#[inline]fn partial_cmp(&self, other: &Acc) -> Option<Ordering> {(**self).partial_cmp(other)}}impl PartialOrd<Account> for &Acc {#[inline]fn partial_cmp(&self, other: &Account) -> Option<Ordering> {other.partial_cmp(self).map(Ordering::reverse)}}impl PartialOrd<Account> for &str {#[inline]fn partial_cmp(&self, other: &Account) -> Option<Ordering> {other.partial_cmp(self).map(Ordering::reverse)}}impl PartialOrd<Account> for Acc {#[inline]fn partial_cmp(&self, other: &Account) -> Option<Ordering> {other.partial_cmp(self).map(Ordering::reverse)}}impl PartialOrd<Account> for Cow<'_, Acc> {#[inline]fn partial_cmp(&self, other: &Account) -> Option<Ordering> {other.partial_cmp(self).map(Ordering::reverse)}}impl PartialOrd<Account> for Cow<'_, str> {#[inline]fn partial_cmp(&self, other: &Account) -> Option<Ordering> {other.partial_cmp(self).map(Ordering::reverse)}}impl PartialOrd<Account> for String {#[inline]fn partial_cmp(&self, other: &Account) -> Option<Ordering> {other.partial_cmp(self).map(Ordering::reverse)}}impl PartialOrd<Account> for str {#[inline]fn partial_cmp(&self, other: &Account) -> Option<Ordering> {other.partial_cmp(self).map(Ordering::reverse)}}impl PartialOrd<Cow<'_, Acc>> for Account {fn partial_cmp(&self, other: &Cow<'_, Acc>) -> Option<Ordering> {self.partial_cmp(&**other)}}impl PartialOrd<Cow<'_, str>> for Account {fn partial_cmp(&self, other: &Cow<'_, str>) -> Option<Ordering> {self.partial_cmp(&**other)}}impl PartialOrd<String> for Account {#[inline]fn partial_cmp(&self, other: &String) -> Option<Ordering> {self.partial_cmp(&**other)}}impl PartialOrd<str> for Account {#[inline]fn partial_cmp(&self, other: &str) -> Option<Ordering> {(**self).partial_cmp(other)}}impl TryFrom<&str> for Account {type Error = AccountError;#[inline]fn try_from(name: &str) -> Result<Self, Self::Error> {<&Acc>::try_from(name).map(Self::from)}}impl TryFrom<String> for Account {type Error = <Self as TryFrom<&'static str>>::Error;#[inline]fn try_from(name: String) -> Result<Self, Self::Error> {ensure!(is_valid_account_name(&name), AccountSnafu { name });Ok(Self { name })}}#[derive(Debug, Snafu)]#[snafu(display("invalid account: {name:?}"))]pub struct AccountError {name: String,backtrace: Backtrace,}struct Ancestors<'a> {next: Option<&'a Acc>,}impl FusedIterator for Ancestors<'_> {}impl<'a> Iterator for Ancestors<'a> {type Item = &'a Acc;fn next(&mut self) -> Option<Self::Item> {let next = self.next?;self.next = next.parent();Some(next)}}#[derive(Clone, Debug)]pub struct Segments<'a> {inner: Split<'a, char>,}impl DoubleEndedIterator for Segments<'_> {delegate! {to self.inner {fn next_back(&mut self) -> Option<Self::Item>;}}}impl FusedIterator for Segments<'_> {}impl<'a> Iterator for Segments<'a> {type Item = &'a str;delegate! {to self.inner {fn next(&mut self) -> Option<Self::Item>;}}}fn is_valid_account_name(name: &str) -> bool {lazy_regex::regex_is_match!(r#"^(?:Assets|Equity|Expenses|Income|Liabilities)(?::[\p{Lu}\p{Nd}][-\p{L}\p{Nd}]*)*$"#,name)}fn is_valid_account_segment(name: &str) -> bool {lazy_regex::regex_is_match!(r#"^(?:[\p{Lu}\p{Nd}][-\p{L}\p{Nd}]*)$"#, name)}
[package]name = "beancount-types"version = "0.0.0-dev.0"edition = "2021"# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html[dependencies]arrayvec = "0.7.2"delegate = "0.8.0"lazy-regex = "2.2.2"once_cell = "1.9.0"regex = "1.5.4"rust_decimal = "1.21.0"snafu = "0.7.0"time = "0.3.7"[dev-dependencies]insta = "1.12.0"proptest = "1.0.0"static_assertions = "1.1.0"test-case = "2.2.1"[features]
name = "beancount-types"version = "0.0.0-dev.0"dependencies = ["arrayvec","delegate","insta","lazy-regex","once_cell","proptest","regex","rust_decimal","snafu","static_assertions","test-case","time",][[package]]name = "bit-set"version = "0.5.3"source = "registry+https://github.com/rust-lang/crates.io-index"checksum = "0700ddab506f33b20a03b13996eccd309a48e5ff77d0d95926aa0210fb4e95f1"dependencies = ["bit-vec",][[package]]name = "bit-vec"version = "0.6.3"source = "registry+https://github.com/rust-lang/crates.io-index"checksum = "349f9b6a179ed607305526ca489b34ad0a41aed5f7980fa90eb03160b69598fb"[[package]]name = "bitflags"version = "1.3.2"source = "registry+https://github.com/rust-lang/crates.io-index"checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"[[package]]name = "byteorder"version = "1.4.3"source = "registry+https://github.com/rust-lang/crates.io-index"checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610"[[package]]name = "cfg-if"version = "1.0.0"source = "registry+https://github.com/rust-lang/crates.io-index"checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"[[package]]name = "console"version = "0.15.1"source = "registry+https://github.com/rust-lang/crates.io-index"checksum = "89eab4d20ce20cea182308bca13088fecea9c05f6776cf287205d41a0ed3c847"dependencies = ["encode_unicode","libc","once_cell","terminal_size","winapi",][[package]]name = "delegate"version = "0.8.0"source = "registry+https://github.com/rust-lang/crates.io-index"checksum = "082a24a9967533dc5d743c602157637116fc1b52806d694a5a45e6f32567fcdd"dependencies = ["proc-macro2","quote","syn",][[package]]name = "doc-comment"version = "0.3.3"source = "registry+https://github.com/rust-lang/crates.io-index"checksum = "fea41bba32d969b513997752735605054bc0dfa92b4c56bf1189f2e174be7a10"[[package]]name = "encode_unicode"version = "0.3.6"source = "registry+https://github.com/rust-lang/crates.io-index"checksum = "a357d28ed41a50f9c765dbfe56cbc04a64e53e5fc58ba79fbc34c10ef3df831f"[[package]]name = "fastrand"version = "1.8.0"source = "registry+https://github.com/rust-lang/crates.io-index"checksum = "a7a407cfaa3385c4ae6b23e84623d48c2798d06e3e6a1878f7f59f17b3f86499"dependencies = ["instant",][[package]]name = "fnv"version = "1.0.7"source = "registry+https://github.com/rust-lang/crates.io-index"checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1"[[package]]
name = "insta"version = "1.19.1"source = "registry+https://github.com/rust-lang/crates.io-index"checksum = "fc61e98be01e89296f3343a878e9f8ca75a494cb5aaf29df65ef55734aeb85f5"dependencies = ["console","linked-hash-map","once_cell","similar","yaml-rust",][[package]]name = "instant"version = "0.1.12"source = "registry+https://github.com/rust-lang/crates.io-index"checksum = "7a5bbe824c507c5da5956355e86a746d82e0e1464f65d862cc5e71da70e94b2c"dependencies = ["cfg-if",][[package]]name = "lazy-regex"version = "2.3.0"source = "registry+https://github.com/rust-lang/crates.io-index"checksum = "b6b12f2eb6ed7d39405c5eb25a034b4c106a9ad87a6d9be3298de6c5f32fd57d"dependencies = ["lazy-regex-proc_macros","once_cell","regex",][[package]]name = "lazy-regex-proc_macros"version = "2.3.0"source = "registry+https://github.com/rust-lang/crates.io-index"checksum = "f2496e5264069bc726ccf37eb76b9cd89406ae110d836c3f76729f99c8a23293"dependencies = ["proc-macro2","quote","regex","syn",][[package]]name = "lazy_static"version = "1.4.0"source = "registry+https://github.com/rust-lang/crates.io-index"checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"[[package]]name = "libc"version = "0.2.132"source = "registry+https://github.com/rust-lang/crates.io-index"checksum = "8371e4e5341c3a96db127eb2465ac681ced4c433e01dd0e938adbef26ba93ba5"[[package]]name = "linked-hash-map"version = "0.5.6"source = "registry+https://github.com/rust-lang/crates.io-index"checksum = "0717cef1bc8b636c6e1c1bbdefc09e6322da8a9321966e8928ef80d20f7f770f"[[package]]name = "memchr"version = "2.5.0"source = "registry+https://github.com/rust-lang/crates.io-index"checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d"[[package]]
][[package]]name = "num_threads"version = "0.1.6"source = "registry+https://github.com/rust-lang/crates.io-index"checksum = "2819ce041d2ee131036f4fc9d6ae7ae125a3a40e97ba64d04fe799ad9dabbb44"dependencies = ["libc",][[package]]name = "once_cell"version = "1.14.0"source = "registry+https://github.com/rust-lang/crates.io-index"checksum = "2f7254b99e31cad77da24b08ebf628882739a608578bb1bcdfc1f9c21260d7c0"[[package]]name = "ppv-lite86"version = "0.2.16"source = "registry+https://github.com/rust-lang/crates.io-index"checksum = "eb9f9e6e233e5c4a35559a617bf40a4ec447db2e84c20b55a6f83167b7e57872"[[package]]name = "proc-macro-error"version = "1.0.4"source = "registry+https://github.com/rust-lang/crates.io-index"checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c"dependencies = ["proc-macro-error-attr","proc-macro2","quote","syn","version_check",][[package]]name = "proc-macro-error-attr"version = "1.0.4"source = "registry+https://github.com/rust-lang/crates.io-index"checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869"dependencies = ["proc-macro2","quote","version_check",
name = "proptest"version = "1.0.0"source = "registry+https://github.com/rust-lang/crates.io-index"checksum = "1e0d9cc07f18492d879586c92b485def06bc850da3118075cd45d50e9c95b0e5"dependencies = ["bit-set","bitflags","byteorder","lazy_static","num-traits","quick-error 2.0.1","rand","rand_chacha","rand_xorshift","regex-syntax","rusty-fork","tempfile",][[package]]name = "quick-error"version = "1.2.3"source = "registry+https://github.com/rust-lang/crates.io-index"checksum = "a1d01941d82fa2ab50be1e79e6714289dd7cde78eba4c074bc5a4374f650dfe0"[[package]]name = "quick-error"version = "2.0.1"source = "registry+https://github.com/rust-lang/crates.io-index"checksum = "a993555f31e5a609f617c12db6250dedcac1b0a85076912c436e6fc9b2c8e6a3"[[package]]
][[package]]name = "rand"version = "0.8.5"source = "registry+https://github.com/rust-lang/crates.io-index"checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404"dependencies = ["libc","rand_chacha","rand_core",][[package]]name = "rand_chacha"version = "0.3.1"source = "registry+https://github.com/rust-lang/crates.io-index"checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88"dependencies = ["ppv-lite86","rand_core",][[package]]name = "rand_core"version = "0.6.3"source = "registry+https://github.com/rust-lang/crates.io-index"checksum = "d34f1408f55294453790c48b2f1ebbb1c5b4b7563eb1f418bcfcfdbb06ebb4e7"dependencies = ["getrandom",][[package]]name = "rand_xorshift"version = "0.3.0"source = "registry+https://github.com/rust-lang/crates.io-index"checksum = "d25bf25ec5ae4a3f1b92f929810509a2f53d7dca2f50b794ff57e3face536c8f"dependencies = ["rand_core",][[package]]name = "redox_syscall"version = "0.2.16"source = "registry+https://github.com/rust-lang/crates.io-index"checksum = "fb5a58c1855b4b6819d59012155603f0b22ad30cad752600aadfcb695265519a"dependencies = ["bitflags",][[package]]name = "regex"version = "1.6.0"source = "registry+https://github.com/rust-lang/crates.io-index"checksum = "4c4eb3267174b8c6c2f654116623910a0fef09c4753f8dd83db29c48a0df988b"dependencies = ["aho-corasick","memchr","regex-syntax",][[package]]name = "regex-syntax"version = "0.6.27"source = "registry+https://github.com/rust-lang/crates.io-index"checksum = "a3f87b73ce11b1619a3c6332f45341e0047173771e8b8b73f87bfeefb7b56244"[[package]]name = "remove_dir_all"version = "0.5.3"source = "registry+https://github.com/rust-lang/crates.io-index"checksum = "3acd125665422973a33ac9d3dd2df85edad0f4ae9b00dafb1a05e43a9f5ef8e7"dependencies = ["winapi",
[[package]]name = "similar"version = "2.2.0"source = "registry+https://github.com/rust-lang/crates.io-index"checksum = "62ac7f900db32bf3fd12e0117dd3dc4da74bc52ebaac97f39668446d89694803"[[package]]name = "snafu"version = "0.7.1"source = "registry+https://github.com/rust-lang/crates.io-index"checksum = "5177903bf45656592d9eb5c0e22f408fc023aae51dbe2088889b71633ba451f2"dependencies = ["doc-comment","snafu-derive",][[package]]name = "snafu-derive"version = "0.7.1"source = "registry+https://github.com/rust-lang/crates.io-index"checksum = "410b26ed97440d90ced3e2488c868d56a86e2064f5d7d6f417909b286afe25e5"dependencies = ["heck","proc-macro2","quote","syn",][[package]]name = "static_assertions"version = "1.1.0"source = "registry+https://github.com/rust-lang/crates.io-index"checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f"[[package]]name = "syn"version = "1.0.99"source = "registry+https://github.com/rust-lang/crates.io-index"checksum = "58dbef6ec655055e20b86b15a8cc6d439cca19b667537ac6a1369572d151ab13"dependencies = ["proc-macro2","quote","unicode-ident",][[package]]name = "tempfile"version = "3.3.0"source = "registry+https://github.com/rust-lang/crates.io-index"checksum = "5cdb1ef4eaeeaddc8fbd371e5017057064af0911902ef36b39801f67cc6d79e4"dependencies = ["cfg-if","fastrand","libc","redox_syscall","remove_dir_all","winapi",][[package]]name = "terminal_size"version = "0.1.17"source = "registry+https://github.com/rust-lang/crates.io-index"checksum = "633c1a546cee861a1a6d0dc69ebeca693bf4296661ba7852b9d21d159e0506df"dependencies = ["libc","winapi",][[package]]name = "test-case"version = "2.2.1"source = "registry+https://github.com/rust-lang/crates.io-index"checksum = "07aea929e9488998b64adc414c29fe5620398f01c2e3f58164122b17e567a6d5"dependencies = ["test-case-macros",][[package]]name = "test-case-macros"version = "2.2.1"source = "registry+https://github.com/rust-lang/crates.io-index"checksum = "c95968eedc6fc4f5c21920e0f4264f78ec5e4c56bb394f319becc1a5830b3e54"dependencies = ["cfg-if","proc-macro-error","proc-macro2","quote","syn",][[package]]name = "time"version = "0.3.14"source = "registry+https://github.com/rust-lang/crates.io-index"checksum = "3c3f9a28b618c3a6b9251b6908e9c99e04b9e5c02e6581ccbb67d59c34ef7f9b"dependencies = ["libc","num_threads",]
[[package]]name = "version_check"version = "0.9.4"source = "registry+https://github.com/rust-lang/crates.io-index"checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f"[[package]]name = "wait-timeout"version = "0.2.0"source = "registry+https://github.com/rust-lang/crates.io-index"checksum = "9f200f5b12eb75f8c1ed65abd4b2db8a6e1b138a20de009dacee265a2498f3f6"dependencies = ["libc",][[package]]name = "wasi"version = "0.11.0+wasi-snapshot-preview1"source = "registry+https://github.com/rust-lang/crates.io-index"checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423"[[package]]name = "winapi"version = "0.3.9"source = "registry+https://github.com/rust-lang/crates.io-index"checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419"dependencies = ["winapi-i686-pc-windows-gnu","winapi-x86_64-pc-windows-gnu",][[package]]name = "winapi-i686-pc-windows-gnu"version = "0.4.0"source = "registry+https://github.com/rust-lang/crates.io-index"checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"[[package]]name = "winapi-x86_64-pc-windows-gnu"version = "0.4.0"source = "registry+https://github.com/rust-lang/crates.io-index"checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"[[package]]name = "yaml-rust"version = "0.4.5"source = "registry+https://github.com/rust-lang/crates.io-index"checksum = "56c1936c4cc7a1c9ab21a1ebb602eb942ba868cbd44a99cb7cdc5892335e1c85"dependencies = ["linked-hash-map",]