Compare commits

...

10 commits

Author SHA1 Message Date
Alain Zscheile
b1af3da189 bump deps 2022-12-24 13:35:36 +01:00
Alain Zscheile
6ec3af5999 fix clippy warnings 2022-10-14 12:15:13 +02:00
Alain Zscheile
954df2f86a cargo upgrade 2022-10-14 12:11:19 +02:00
Alain Zscheile
5684348a5d update .gitignore for Nix stuff 2022-10-14 12:03:16 +02:00
zseri
3a840afda4 nix-flakify 2021-07-19 23:52:31 +02:00
Erik Zscheile
13e69f5b9c cargo upgrade 2020-12-29 17:27:10 +01:00
Erik Zscheile
c3fd68249d get rid of 3 dependencies 2020-12-29 17:24:43 +01:00
Erik Zscheile
cbd0ab82bd +option '--highlight-only' 2019-12-23 22:01:53 +01:00
Erik Zscheile
35541de631 split table at half-years 2019-12-23 21:48:45 +01:00
Erik Zscheile
83e9219049 use par_sort 2019-12-23 21:34:49 +01:00
10 changed files with 3252 additions and 493 deletions

2
.gitignore vendored
View file

@ -1,3 +1,5 @@
result
result-*
/target
/flamegraph.svg
/perf.data*

844
Cargo.lock generated

File diff suppressed because it is too large Load diff

2676
Cargo.nix Normal file

File diff suppressed because it is too large Load diff

View file

@ -7,15 +7,12 @@ edition = "2018"
[dependencies]
chrono = { version = "0.4", features = ["serde"] }
csv = "1.1"
encoding = "0.2"
fixed = { version = "0.5", features = ["serde", "std"] }
itertools = "0.8"
prettytable = { version = "0.8", package = "prettytable-rs" }
rayon = "1.3"
readfilez = "0.2"
ron = "0.5"
fixed = { version = "1.20", features = ["serde", "std"] }
itertools = "0.10"
prettytable = { version = "0.9", package = "prettytable-rs" }
rayon = "1.6"
serde = { version = "1.0", features = ["derive"] }
term = "0.5"
term = "0.7"
thiserror = "1.0"
[profile.release]

43
flake.lock Normal file
View file

@ -0,0 +1,43 @@
{
"nodes": {
"nixpkgs": {
"locked": {
"lastModified": 1671884884,
"narHash": "sha256-JHX4CdMwDdYFeHzx2gKTe66Dx6vE8WXtND0twqann1g=",
"owner": "nixos",
"repo": "nixpkgs",
"rev": "ff76349c4f6ef483ecfd2591ce424c741925b111",
"type": "github"
},
"original": {
"owner": "nixos",
"ref": "master",
"repo": "nixpkgs",
"type": "github"
}
},
"root": {
"inputs": {
"nixpkgs": "nixpkgs",
"yz-flake-utils": "yz-flake-utils"
}
},
"yz-flake-utils": {
"locked": {
"lastModified": 1660779307,
"narHash": "sha256-WiuDu1qAj7I1GY7FlNK5cMaCa94CKgdv0cumUXCavww=",
"owner": "YZITE",
"repo": "flake-utils",
"rev": "8fecd51bdf7138bfb6b7ac3340d0f65e2680556f",
"type": "github"
},
"original": {
"owner": "YZITE",
"repo": "flake-utils",
"type": "github"
}
}
},
"root": "root",
"version": 7
}

14
flake.nix Normal file
View file

@ -0,0 +1,14 @@
{
description = "PSD Bank N. CSV summarizer";
inputs = {
nixpkgs.url = "github:nixos/nixpkgs/master";
yz-flake-utils.url = "github:YZITE/flake-utils";
};
outputs = { nixpkgs, yz-flake-utils, ... }:
yz-flake-utils.lib.mkFlakeFromProg {
contentAddressedByDefault = false;
prevpkgs = nixpkgs;
progname = "psdn-tacsvs";
drvBuilder = final: prev: (import ./Cargo.nix { pkgs = final; }).rootCrate.build;
};
}

76
src/codec.rs Normal file
View file

@ -0,0 +1,76 @@
use std::io::{self, Read};
pub struct Latin12Utf8Reader<X> {
inner: std::io::Bytes<X>,
buf: Vec<u8>,
}
impl<X: Read> Latin12Utf8Reader<X> {
pub fn new(x: X) -> Self {
Self {
inner: x.bytes(),
buf: Default::default(),
}
}
fn move_to_dest(&mut self, buf: &mut [u8]) -> usize {
let ret = std::cmp::min(buf.len(), self.buf.len());
debug_assert!(ret > 0);
buf[..ret].copy_from_slice(&self.buf[..ret]);
let _ = self.buf.drain(..ret);
ret
}
}
impl<X: Read> Read for Latin12Utf8Reader<X> {
fn read(&mut self, mut buf: &mut [u8]) -> io::Result<usize> {
if buf.is_empty() {
return Ok(0);
}
let mut ret = 0;
if !self.buf.is_empty() {
let ret2 = self.move_to_dest(buf);
buf = &mut buf[ret2..];
ret = ret2;
}
while !buf.is_empty() {
if let Some(y) = self.inner.next() {
match y {
Ok(x) => {
let x = if x <= 0x7f {
x as char
} else {
std::char::from_u32(x as u32).ok_or_else(|| {
std::io::Error::new(
std::io::ErrorKind::InvalidData,
format!("got invalid input character: {:#02x}", x),
)
})?
};
let xl = x.len_utf8();
if buf.len() >= xl {
x.encode_utf8(buf);
buf = &mut buf[xl..];
} else {
let mut tmp = [0; 4];
x.encode_utf8(&mut tmp[..]);
self.buf.extend(tmp.iter().take(xl).copied());
ret += self.move_to_dest(buf);
break;
}
}
Err(x) if ret == 0 => {
return Err(x);
}
Err(_) => {
// ignore error
break;
}
}
} else {
break;
}
}
Ok(ret)
}
}

View file

@ -1,3 +1,5 @@
mod codec;
/// simple typed helper enums
mod simple_enums;
@ -12,9 +14,8 @@ fn main() {
use {
chrono::Datelike,
encoding::types::Encoding,
itertools::Itertools,
prettytable::{cell, format, row, Table},
prettytable::{format, row, Table},
rayon::prelude::*,
std::{
collections::{BTreeMap, HashSet},
@ -23,8 +24,9 @@ fn main() {
};
let mut highlight = HashSet::new();
let hl_only = args[0] == "--highlight-only";
if args[0] == "--highlight" {
if args[0] == "--highlight" || hl_only {
args.remove(0);
let eo_selst = args.iter().take_while(|i| *i != ";").count();
highlight = args
@ -38,20 +40,13 @@ fn main() {
let mut dat: Vec<_> = args
.into_par_iter()
.flat_map(|i| {
let fh =
readfilez::read_from_file(std::fs::File::open(i)).expect("unable to open file");
let tmp = encoding::all::ISO_8859_1
.decode(&*fh, encoding::types::DecoderTrap::Replace)
.expect("got invalid latin-1 data");
std::mem::drop(fh);
let mut rdr = csv::ReaderBuilder::new()
.delimiter(b';')
.flexible(true)
.has_headers(false)
.from_reader(tmp.as_bytes());
.from_reader(codec::Latin12Utf8Reader::new(
std::fs::File::open(i).expect("unable to open file"),
));
let mut recsit = rdr.records().skip(8);
@ -85,9 +80,9 @@ fn main() {
match pres {
Ok(tl) => {
if tl.direction == simple_enums::TransactionDirection::Haben
&& tl.waehrung == simple_enums::Waehrung::EUR
&& tl.waehrung == simple_enums::Waehrung::Eur
&& !tl.p_other.is_empty()
&& tl.p_other.find(" ZINS BIS ").is_none()
&& !tl.p_other.contains(" ZINS BIS ")
{
idat.push(tl)
} else {
@ -103,17 +98,16 @@ fn main() {
})
.collect();
let mut stdout = term::stdout().unwrap();
dat.par_sort();
dat.sort();
let oldlen = dat.len();
let mut newlen = 0usize;
let mut stdout = term::stdout().unwrap();
let mut accu = BTreeMap::<
(i32, bool, String),
(usize, transaction::TransactionValue, String, usize),
>::new();
let mut newlen = 0usize;
for i in dat.into_iter().dedup() {
newlen += 1;
let mut ent = accu
@ -164,14 +158,28 @@ fn main() {
);
table.set_titles(row!["Jahr", "Einzahler", "Zahlungen", "Summe"]);
let mut prev_yuhj = Option::<String>::None;
for (k, v) in accu.iter_mut() {
let yearuhj = format!("{} {}", k.0, if k.1 { "II" } else { "I" });
v.2 += &std::iter::repeat(' ').take(pdsp - v.3).collect::<String>();
table.add_row(if highlight.contains(&*k.2) {
row![yearuhj, FYBdb-> k.2, r-> v.0.to_string(), Fgbr-> v.2]
} else {
row![yearuhj, k.2, r-> v.0.to_string(), r-> v.2]
});
let is_hl = highlight.contains(&*k.2);
if !hl_only || is_hl {
let mut yearuhj = format!("{} {}I", k.0, if k.1 { "I" } else { "" });
let is_ny = prev_yuhj.as_ref().map(|i| i != &yearuhj);
v.2 += &" ".repeat(pdsp - v.3);
if is_ny.unwrap_or(false) {
table.add_row(row!["", "", "", ""]);
}
if is_ny.unwrap_or(true) {
prev_yuhj = Some(yearuhj.clone());
} else {
yearuhj.clear();
}
table.add_row(if !hl_only && is_hl {
row![yearuhj, FYBdb-> k.2, r-> v.0.to_string(), Fgbr-> v.2]
} else {
row![yearuhj, k.2, r-> v.0.to_string(), r-> v.2]
});
}
}
table

View file

@ -29,15 +29,18 @@ use {
std::fmt,
};
#[derive(Clone, Copy, Debug, Deserialize, Eq, Hash, Ord, PartialEq, PartialOrd, Serialize)]
#[derive(Clone, Copy, Deserialize, Eq, Hash, Ord, PartialEq, PartialOrd, Serialize)]
pub enum Waehrung {
EUR,
USD,
Eur,
Usd,
}
impl fmt::Display for Waehrung {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{:?}", self)
write!(f, "{}", match self {
Self::Eur => "EUR",
Self::Usd => "USD",
})
}
}
@ -46,8 +49,8 @@ impl std::str::FromStr for Waehrung {
fn from_str(s: &str) -> Result<Self, Self::Err> {
Ok(match s {
"EUR" => Waehrung::EUR,
"USD" => Waehrung::USD,
"EUR" => Self::Eur,
"USD" => Self::Usd,
_ => return Err(parser_error::Waehrung),
})
}

View file

@ -5,7 +5,7 @@ use thiserror::Error;
pub type TransactionValue = fixed::types::U53F11;
#[derive(Clone, Debug, Deserialize, Eq, Ord, PartialEq, PartialOrd, Serialize)]
#[derive(Clone, Deserialize, Eq, Ord, PartialEq, PartialOrd, Serialize)]
pub struct TransactionLine {
pub d_buchungs: NaiveDate,
pub d_valuta: NaiveDate,