Implement metadata on transactions

korrat
Dec 17, 2022, 9:09 AM
SEEWF7KXEUNPVQBZUZ3ZXU4BIADFUEULIKAD3OMKSNRBDNJXRPLQC

Dependencies

  • [2] R7S2CWF7 Add type for account segments
  • [3] T2S6UAVJ Include builder methods on beancount-types
  • [4] YDK6X6PP add a library of important types for beancount
  • [5] 2JBFREZG enable additional warnings
  • [*] UESS5YZE migrate dependencies into workspace manifest

Change contents

  • edit in common/beancount-types/src/transaction.rs at line 154
    [4.1311]
    [4.1311]
    pub metadata: TransactionMetadata,
  • replacement in common/beancount-types/src/transaction.rs at line 163
    [3.1973][3.1973:2042]()
    let (flag, payee, narration, postings) = Default::default();
    [3.1973]
    [3.2042]
    let (flag, metadata, payee, narration, postings) = Default::default();
  • edit in common/beancount-types/src/transaction.rs at line 170
    [3.2136]
    [3.2136]
    metadata,
  • edit in common/beancount-types/src/transaction.rs at line 180
    [3.2313]
    [3.2313]
    self
    }
    #[inline]
    pub fn add_key_value(
    &mut self,
    key: impl Into<MetadataKey>,
    value: impl Into<MetadataValue>,
    ) -> &mut Self {
    self.metadata.add_key_value(key, value);
    self
    }
    #[inline]
    pub fn add_link(&mut self, link: impl Into<Link>) -> &mut Self {
    self.metadata.add_link(link);
  • edit in common/beancount-types/src/transaction.rs at line 206
    [3.2544]
    [3.2544]
    }
    #[inline]
    pub fn clear_metadata(&mut self) -> &mut Self {
    self.metadata = Default::default();
    self
    }
    #[inline]
    pub fn clear_narration(&mut self) -> &mut Self {
    self.narration = Default::default();
    self
    }
    #[inline]
    pub fn clear_payee(&mut self) -> &mut Self {
    self.payee = Default::default();
    self
    }
    #[inline]
    pub fn clear_postings(&mut self) -> &mut Self {
    self.postings.clear();
    self
    }
    #[inline]
    pub fn complete(&mut self) -> &mut Self {
    self.set_flag(Flag::Complete)
  • edit in common/beancount-types/src/transaction.rs at line 236
    [3.2550]
    [4.1347]
    #[inline]
    pub fn incomplete(&mut self) -> &mut Self {
    self.set_flag(Flag::Incomplete)
    }
    #[inline]
    pub fn set_date(&mut self, date: Date) -> &mut Self {
    self.date = date;
    self
    }
    #[inline]
    pub fn set_flag(&mut self, flag: Flag) -> &mut Self {
    self.flag = flag;
    self
    }
    #[inline]
    pub fn set_metadata(&mut self, metadata: impl Into<TransactionMetadata>) -> &mut Self {
    self.metadata = metadata.into();
    self
    }
    #[inline]
    pub fn set_narration(&mut self, narration: impl Into<String>) -> &mut Self {
    self.narration = Some(narration.into());
    self
    }
    #[inline]
    pub fn set_payee(&mut self, payee: impl Into<String>) -> &mut Self {
    self.payee = Some(payee.into());
    self
    }
    #[inline]
    pub fn set_postings(&mut self, postings: impl Into<Vec<Posting>>) -> &mut Self {
    self.postings = postings.into();
    self
    }
    #[inline]
    pub fn with_metadata(&mut self, block: impl FnOnce(&mut TransactionMetadata)) -> &mut Self {
    block(&mut self.metadata);
    self
    }
    #[inline]
    pub fn with_postings(&mut self, block: impl FnOnce(&mut Vec<Posting>)) -> &mut Self {
    block(&mut self.postings);
    self
    }
    }
  • edit in common/beancount-types/src/transaction.rs at line 297
    [4.1525]
    [4.1525]
    metadata,
  • edit in common/beancount-types/src/transaction.rs at line 310
    [4.1931]
    [4.1931]
    write!(f, "{metadata}")?;
  • replacement in common/beancount-types/src/transaction.rs at line 321
    [4.2042][4.2042:2110]()
    #[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
    [4.2042]
    [4.3666]
    #[derive(Clone, Copy, Debug, Default, Eq, Hash, Ord, PartialEq, PartialOrd)]
  • edit in common/beancount-types/src/transaction.rs at line 323
    [4.3682]
    [4.2137]
    #[default]
  • file addition: metadata.rs (---r------)
    [4.44]
    use core::borrow::Borrow;
    use core::fmt::Display;
    use core::ops::Deref;
    use core::str::FromStr;
    use alloc::collections::BTreeMap;
    use delegate::delegate;
    use miette::Diagnostic;
    use snafu::ensure;
    use snafu::Backtrace;
    use snafu::Snafu;
    #[derive(Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
    #[repr(transparent)]
    pub struct Key {
    name: String,
    }
    impl Display for Key {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
    f.write_str(&self.name)
    }
    }
    impl FromStr for Key {
    type Err = KeyError;
    #[inline]
    fn from_str(name: &str) -> Result<Self, Self::Err> {
    ensure!(is_valid_key(name), KeySnafu { name });
    let name = name.to_owned();
    Ok(Self { name })
    }
    }
    impl TryFrom<String> for Key {
    type Error = KeyError;
    fn try_from(name: String) -> Result<Self, Self::Error> {
    ensure!(is_valid_key(&name), KeySnafu { name });
    Ok(Self { name })
    }
    }
    #[derive(Debug, Diagnostic, Snafu)]
    pub struct KeyError {
    backtrace: Backtrace,
    name: String,
    }
    #[derive(Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
    #[repr(transparent)]
    pub struct Link {
    name: String,
    }
    impl Borrow<Lnk> for Link {
    fn borrow(&self) -> &Lnk {
    self
    }
    }
    impl Deref for Link {
    type Target = Lnk;
    fn deref(&self) -> &Self::Target {
    #[allow(unsafe_code)]
    unsafe {
    // SAFETY: self.name is a valid link name, by construction
    Self::Target::from_unchecked(&self.name)
    }
    }
    }
    impl Display for Link {
    delegate! {
    to self.name {
    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result;
    }
    }
    }
    impl From<&Lnk> for Link {
    #[inline]
    fn from(link: &Lnk) -> Self {
    link.to_owned()
    }
    }
    impl FromStr for Link {
    type Err = LinkError;
    #[inline]
    fn from_str(name: &str) -> Result<Self, Self::Err> {
    <&Lnk>::try_from(name).map(Self::from)
    }
    }
    impl TryFrom<String> for Link {
    type Error = LinkError;
    #[inline]
    fn try_from(name: String) -> Result<Self, Self::Error> {
    ensure!(is_valid_link_name(&name), LinkSnafu { name });
    Ok(Self { name })
    }
    }
    #[derive(Debug, Diagnostic, Snafu)]
    pub struct LinkError {
    name: String,
    backtrace: Backtrace,
    }
    #[derive(Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
    #[repr(transparent)]
    pub struct Lnk {
    name: str,
    }
    impl Lnk {
    #[allow(unsafe_code)]
    #[inline]
    const unsafe fn from_unchecked(name: &str) -> &Self {
    let name: *const _ = name;
    let name = name as *const _;
    unsafe { &*name }
    }
    }
    impl ToOwned for Lnk {
    type Owned = Link;
    #[inline]
    fn to_owned(&self) -> Self::Owned {
    let name = self.name.to_owned();
    Self::Owned { name }
    }
    }
    impl<'l> TryFrom<&'l str> for &'l Lnk {
    type Error = LinkError;
    #[inline]
    fn try_from(name: &'l str) -> Result<Self, Self::Error> {
    ensure!(is_valid_link_name(name), LinkSnafu { name });
    Ok(
    #[allow(unsafe_code)]
    unsafe {
    // SAFETY: we have ensured that `name` is a valid link.
    Lnk::from_unchecked(name)
    },
    )
    }
    }
    #[derive(Clone, Debug, Default, Eq, Hash, PartialEq)]
    pub struct Transaction {
    pub key_value: BTreeMap<Key, Value>,
    pub links: Vec<Link>,
    }
    impl Transaction {
    #[inline]
    pub fn add_link(&mut self, link: impl Into<Link>) -> &mut Self {
    self.links.push(link.into());
    self
    }
    #[inline]
    pub fn add_key_value(&mut self, key: impl Into<Key>, value: impl Into<Value>) -> &mut Self {
    self.key_value.insert(key.into(), value.into());
    self
    }
    }
    impl Display for Transaction {
    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
    for link in &self.links {
    link.fmt(f)?
    }
    Ok(())
    }
    }
    #[derive(Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
    pub enum Value {
    String(String),
    }
    impl Display for Value {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
    match self {
    Value::String(inner) => write!(f, "{inner:?}"),
    }
    }
    }
    impl<S> From<S> for Value
    where
    S: Into<String>,
    {
    fn from(value: S) -> Self {
    Self::String(value.into())
    }
    }
    fn is_valid_key(name: &str) -> bool {
    lazy_regex::regex_is_match!(r"^(:?[a-z][a-zA-Z0-9\-_]+)$", name)
    }
    fn is_valid_link_name(name: &str) -> bool {
    lazy_regex::regex_is_match!(r"^(:?\^[A-Za-z0-9\-_/.]+)$", name)
    }
  • edit in common/beancount-types/src/lib.rs at line 12
    [4.4225]
    [4.4225]
    pub use crate::metadata::Key as MetadataKey;
    pub use crate::metadata::Link;
    pub use crate::metadata::Transaction as TransactionMetadata;
    pub use crate::metadata::Value as MetadataValue;
  • edit in common/beancount-types/src/lib.rs at line 31
    [4.5978]
    [4.5978]
    mod metadata;
  • replacement in common/beancount-types/src/cost.rs at line 7
    [4.7653][4.4769:4816]()
    #[derive(Clone, Copy, Debug, Hash, PartialEq)]
    [4.7653]
    [4.7698]
    #[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
  • replacement in common/beancount-types/src/balance.rs at line 9
    [4.9398][4.6266:6319]()
    #[derive(Clone, Debug, Hash, PartialEq, PartialOrd)]
    [4.9398]
    [4.9443]
    #[derive(Clone, Debug, Eq, Hash, PartialEq, PartialOrd)]
  • replacement in common/beancount-types/src/amount.rs at line 128
    [4.10599][4.10599:10629]()
    #[derive(Clone, Copy, Debug)]
    [4.10599]
    [4.10070]
    #[derive(Clone, Copy, Debug, Eq)]
  • edit in common/beancount-types/src/amount.rs at line 133
    [4.10146]
    [4.10630]
    }
    impl Amount {
    pub fn new(amount: Decimal, commodity: Commodity) -> Self {
    Self { amount, commodity }
    }
  • edit in common/beancount-types/src/account.rs at line 710
    [2.1603]
    [2.1603]
    #[inline]
  • edit in common/beancount-types/src/account.rs at line 712
    [2.1661]
    [2.1661]
    let name: *const _ = name;
    let name = name as *const _;
  • edit in common/beancount-types/src/account.rs at line 717
    [2.1798][2.1798:1878]()
    let name: *const _ = name;
    let name = name as *const _;
  • edit in common/beancount-types/Cargo.toml at line 21
    [7.434]
    [7.434]
    tap.workspace = true