use crate::read::RawRow;
use crate::AdapterError;
use btctax_core::{LedgerEvent, PriceProvider, Source};
use std::path::PathBuf;
#[derive(Debug, Clone)]
pub struct SourceFile {
pub path: PathBuf,
}
impl SourceFile {
pub fn new(path: impl Into<PathBuf>) -> Self {
Self { path: path.into() }
}
}
#[derive(Debug, Clone)]
pub struct FileGroup {
pub source: Source,
pub label: String,
pub files: Vec<SourceFile>,
}
#[derive(Debug, Default)]
pub struct GroupOutput {
pub events: Vec<LedgerEvent>,
pub dropped_no_btc: usize,
pub unclassified: usize,
pub parsed_rows: usize,
pub skipped_zero_sat: usize,
}
impl GroupOutput {
pub fn merge(&mut self, o: GroupOutput) {
self.events.extend(o.events);
self.dropped_no_btc += o.dropped_no_btc;
self.unclassified += o.unclassified;
self.parsed_rows += o.parsed_rows;
self.skipped_zero_sat += o.skipped_zero_sat;
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct FileReport {
pub source: Source,
pub label: String,
pub parsed_rows: usize,
pub btc_events: usize,
pub dropped_no_btc: usize,
pub unclassified: usize,
pub skipped_zero_sat: usize,
}
#[derive(Debug, Default)]
pub struct IngestBatch {
pub events: Vec<LedgerEvent>,
pub reports: Vec<FileReport>,
}
pub trait Adapter {
fn source(&self) -> Source;
fn detect(&self, file: &SourceFile) -> Result<bool, AdapterError>;
fn group(&self, files: Vec<SourceFile>) -> Vec<FileGroup>;
fn parse(&self, group: &FileGroup) -> Result<Vec<RawRow>, AdapterError>;
fn normalize(
&self,
group: &FileGroup,
rows: Vec<RawRow>,
prices: &dyn PriceProvider,
) -> Result<GroupOutput, AdapterError>;
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn group_output_merge_accumulates_fr2_counts() {
let mut a = GroupOutput {
dropped_no_btc: 1,
unclassified: 2,
parsed_rows: 3,
skipped_zero_sat: 1,
..Default::default()
};
let b = GroupOutput {
dropped_no_btc: 4,
unclassified: 5,
parsed_rows: 6,
skipped_zero_sat: 2,
events: Vec::new(),
};
a.merge(b);
assert_eq!((a.dropped_no_btc, a.unclassified, a.parsed_rows), (5, 7, 9));
assert_eq!(a.skipped_zero_sat, 3);
}
#[test]
fn trait_is_object_safe() {
fn _takes(_: &dyn Adapter) {}
}
}