Can import data from FinancesManager

This commit is contained in:
2025-05-02 16:37:30 +02:00
parent f220451e6e
commit ee43de1c82
6 changed files with 155 additions and 0 deletions

View File

@ -0,0 +1,107 @@
use std::num::{ParseFloatError, ParseIntError};
#[derive(thiserror::Error, Debug)]
enum FinancesManagerDecodeError {
#[error("Movement entry is not a three-part component! got {0} parts instead of 3!")]
MovementParts(usize),
#[error("Could not decode time!")]
Time(ParseIntError),
#[error("Could not decode amount!")]
Amount(ParseFloatError),
}
#[derive(serde::Deserialize, serde::Serialize)]
pub struct FinancesManagerMovement {
pub label: String,
pub time: u64,
pub amount: f32,
}
#[derive(serde::Deserialize, serde::Serialize)]
pub struct FinancesManagerAccount {
pub name: String,
pub movements: Vec<FinancesManagerMovement>,
}
#[derive(serde::Deserialize, serde::Serialize)]
pub struct FinancesManagerFile {
pub accounts: Vec<FinancesManagerAccount>,
}
impl FinancesManagerFile {
/// Parse a finance manager file
pub fn parse(file: &str) -> anyhow::Result<Self> {
let mut res = Self { accounts: vec![] };
let mut curr_account = None;
for l in file.lines() {
// Check if we reached the end of an account
if l.trim().is_empty() {
if let Some(a) = curr_account {
res.accounts.push(a);
}
curr_account = None;
continue;
}
if l == "==============" {
continue;
}
match &mut curr_account {
// Header
None => {
curr_account = Some(FinancesManagerAccount {
name: l.to_string(),
movements: vec![],
});
}
// Account content
Some(account) => {
let split = l.split(';').collect::<Vec<_>>();
if split.len() != 3 {
return Err(FinancesManagerDecodeError::MovementParts(split.len()).into());
}
account.movements.push(FinancesManagerMovement {
label: split[1].to_string(),
time: split[0]
.parse::<u64>()
.map_err(FinancesManagerDecodeError::Time)?,
amount: split[2]
.parse::<f32>()
.map_err(FinancesManagerDecodeError::Amount)?,
})
}
}
}
// Push last account
Ok(res)
}
/// Encode FinancesManager file
pub fn encode(&self) -> String {
let mut out = String::new();
for account in &self.accounts {
out.push_str(&account.name);
out.push_str("\n==============\n");
for movement in &account.movements {
out.push_str(&format!(
"{};{};{}\n",
movement.time,
movement.label.replace(';', ","),
movement.amount
));
}
out.push_str("\n\n\n");
}
out
}
}