diff --git a/Cargo.lock b/Cargo.lock index bf1c400..fee6985 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -70,6 +70,18 @@ version = "2.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ea8a8b81cacc08888170eef4d13b775126db426d0b348bee9d18c2c1eaf123cf" +[[package]] +name = "dyn-clone" +version = "1.0.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1c7a8fb8a9fbf66c1f703fe16184d10ca0ee9d23be5b4436400408ba54a95005" + +[[package]] +name = "dyn-eq" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c2d035d21af5cde1a6f5c7b444a5bf963520a9f142e5d06931178433d7d5388" + [[package]] name = "iana-time-zone" version = "0.1.63" @@ -116,6 +128,8 @@ version = "0.1.0" dependencies = [ "chrono", "downcast-rs", + "dyn-clone", + "dyn-eq", "solvent", ] diff --git a/Cargo.toml b/Cargo.toml index c925807..b4bac49 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -6,5 +6,6 @@ edition = "2021" [dependencies] chrono = "0.4.41" downcast-rs = "2.0.1" -#dyn-clone = "1.0.19" +dyn-clone = "1.0.19" +dyn-eq = "0.1.3" solvent = "0.8.3" diff --git a/src/main.rs b/src/main.rs index c728461..5870164 100644 --- a/src/main.rs +++ b/src/main.rs @@ -21,7 +21,7 @@ use libdrcr::reporting::{ builders::register_dynamic_builders, calculator::solve_for, steps::{register_lookup_fns, AllTransactionsExceptRetainedEarnings, CalculateIncomeTax}, - ReportingContext, ReportingStep, + DateEofyArgs, DateStartDateEndArgs, ReportingContext, ReportingStep, }; fn main() { @@ -31,13 +31,24 @@ fn main() { let targets: Vec> = vec![ Box::new(CalculateIncomeTax { - date_eofy: NaiveDate::from_ymd_opt(2025, 6, 30).unwrap(), + args: DateEofyArgs { + date_eofy: NaiveDate::from_ymd_opt(2025, 6, 30).unwrap(), + }, }), Box::new(AllTransactionsExceptRetainedEarnings { - date_start: NaiveDate::from_ymd_opt(2024, 7, 1).unwrap(), - date_end: NaiveDate::from_ymd_opt(2025, 6, 30).unwrap(), + args: DateStartDateEndArgs { + date_start: NaiveDate::from_ymd_opt(2024, 7, 1).unwrap(), + date_end: NaiveDate::from_ymd_opt(2025, 6, 30).unwrap(), + }, }), ]; - println!("{:?}", solve_for(targets, context)); + match solve_for(targets, context) { + Ok(steps) => { + for step in steps { + println!("- {}", step.id()); + } + } + Err(err) => panic!("Error: {:?}", err), + } } diff --git a/src/reporting/builders.rs b/src/reporting/builders.rs index 3987725..6d91e61 100644 --- a/src/reporting/builders.rs +++ b/src/reporting/builders.rs @@ -16,12 +16,10 @@ along with this program. If not, see . */ -use chrono::NaiveDate; - use super::{ calculator::{has_step_or_can_build, HasStepOrCanBuild, ReportingGraphDependencies}, - ReportingContext, ReportingProductId, ReportingProductKind, ReportingStep, - ReportingStepDynamicBuilder, ReportingStepId, + DateArgs, DateStartDateEndArgs, ReportingContext, ReportingProductId, ReportingProductKind, + ReportingStep, ReportingStepArgs, ReportingStepDynamicBuilder, ReportingStepId, }; pub fn register_dynamic_builders(context: &mut ReportingContext) { @@ -41,8 +39,7 @@ pub fn register_dynamic_builders(context: &mut ReportingContext) { #[derive(Debug)] pub struct BalancesAtToBalancesBetween { step_name: &'static str, - date_start: NaiveDate, - date_end: NaiveDate, + args: DateStartDateEndArgs, } impl BalancesAtToBalancesBetween { @@ -51,7 +48,7 @@ impl BalancesAtToBalancesBetween { fn can_build( name: &'static str, kind: ReportingProductKind, - args: Vec, + args: &Box, steps: &Vec>, dependencies: &ReportingGraphDependencies, context: &ReportingContext, @@ -62,7 +59,7 @@ impl BalancesAtToBalancesBetween { &ReportingProductId { name, kind: ReportingProductKind::BalancesAt, - args: vec![args[1].clone()], + args: args.clone(), }, steps, dependencies, @@ -82,15 +79,14 @@ impl BalancesAtToBalancesBetween { fn build( name: &'static str, _kind: ReportingProductKind, - args: Vec, + args: Box, _steps: &Vec>, _dependencies: &ReportingGraphDependencies, _context: &ReportingContext, ) -> Box { Box::new(BalancesAtToBalancesBetween { step_name: name, - date_start: NaiveDate::parse_from_str(&args[0], "%Y-%m-%d").unwrap(), - date_end: NaiveDate::parse_from_str(&args[1], "%Y-%m-%d").unwrap(), + args: *args.downcast().unwrap(), }) } } @@ -100,10 +96,7 @@ impl ReportingStep for BalancesAtToBalancesBetween { ReportingStepId { name: self.step_name, product_kinds: &[ReportingProductKind::BalancesBetween], - args: vec![ - self.date_start.format("%Y-%m-%d").to_string(), - self.date_end.format("%Y-%m-%d").to_string(), - ], + args: Box::new(self.args.clone()), } } @@ -112,12 +105,15 @@ impl ReportingStep for BalancesAtToBalancesBetween { _steps: &Vec>, dependencies: &mut ReportingGraphDependencies, ) { + // BalancesAtToBalancesBetween depends on BalancesAt at both time points dependencies.add_dependency( self.id(), ReportingProductId { name: self.step_name, kind: ReportingProductKind::BalancesAt, - args: vec![self.date_start.format("%Y-%m-%d").to_string()], + args: Box::new(DateArgs { + date: self.args.date_start.clone(), + }), }, ); dependencies.add_dependency( @@ -125,7 +121,9 @@ impl ReportingStep for BalancesAtToBalancesBetween { ReportingProductId { name: self.step_name, kind: ReportingProductKind::BalancesAt, - args: vec![self.date_end.format("%Y-%m-%d").to_string()], + args: Box::new(DateArgs { + date: self.args.date_end.clone(), + }), }, ); } @@ -134,8 +132,7 @@ impl ReportingStep for BalancesAtToBalancesBetween { #[derive(Debug)] pub struct UpdateBalancesBetween { step_name: &'static str, - date_start: NaiveDate, - date_end: NaiveDate, + args: DateStartDateEndArgs, } impl UpdateBalancesBetween { @@ -144,7 +141,7 @@ impl UpdateBalancesBetween { fn can_build( name: &'static str, kind: ReportingProductKind, - _args: Vec, + _args: &Box, steps: &Vec>, dependencies: &ReportingGraphDependencies, _context: &ReportingContext, @@ -191,15 +188,14 @@ impl UpdateBalancesBetween { fn build( name: &'static str, _kind: ReportingProductKind, - args: Vec, + args: Box, _steps: &Vec>, _dependencies: &ReportingGraphDependencies, _context: &ReportingContext, ) -> Box { Box::new(UpdateBalancesBetween { step_name: name, - date_start: NaiveDate::parse_from_str(&args[0], "%Y-%m-%d").unwrap(), - date_end: NaiveDate::parse_from_str(&args[1], "%Y-%m-%d").unwrap(), + args: *args.downcast().unwrap(), }) } } @@ -209,10 +205,7 @@ impl ReportingStep for UpdateBalancesBetween { ReportingStepId { name: self.step_name, product_kinds: &[ReportingProductKind::BalancesBetween], - args: vec![ - self.date_start.format("%Y-%m-%d").to_string(), - self.date_end.format("%Y-%m-%d").to_string(), - ], + args: Box::new(self.args.clone()), } } diff --git a/src/reporting/calculator.rs b/src/reporting/calculator.rs index e8fb151..07a1ddc 100644 --- a/src/reporting/calculator.rs +++ b/src/reporting/calculator.rs @@ -113,7 +113,7 @@ pub fn has_step_or_can_build<'a, 'b>( if (builder.can_build)( product.name, product.kind, - product.args.clone(), + &product.args, steps, dependencies, context, @@ -225,7 +225,7 @@ pub fn solve_for( if (builder.can_build)( dependency.dependency.name, dependency.dependency.kind, - dependency.dependency.args.clone(), + &dependency.dependency.args, &steps, &dependencies, &context, diff --git a/src/reporting/mod.rs b/src/reporting/mod.rs index 8bd4012..5e27a52 100644 --- a/src/reporting/mod.rs +++ b/src/reporting/mod.rs @@ -19,9 +19,11 @@ use std::fmt::Debug; use std::{collections::HashMap, fmt::Display}; -use calculator::{ReportingGraphDependencies}; +use calculator::ReportingGraphDependencies; use chrono::NaiveDate; use downcast_rs::Downcast; +use dyn_clone::DynClone; +use dyn_eq::DynEq; pub mod builders; pub mod calculator; @@ -66,12 +68,12 @@ impl ReportingContext { pub struct ReportingProductId { name: &'static str, kind: ReportingProductKind, - args: Vec, + args: Box, } impl Display for ReportingProductId { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - f.write_fmt(format_args!("{}.{:?}{:?}", self.name, self.kind, self.args)) + f.write_fmt(format_args!("{}.{:?}({})", self.name, self.kind, self.args)) } } @@ -102,13 +104,13 @@ pub enum ReportingProductKind { pub struct ReportingStepId { pub name: &'static str, pub product_kinds: &'static [ReportingProductKind], - pub args: Vec, + pub args: Box, } impl Display for ReportingStepId { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { f.write_fmt(format_args!( - "{}{:?}{:?}", + "{}{:?}({})", self.name, self.product_kinds, self.args )) } @@ -138,14 +140,60 @@ pub trait ReportingStep: Debug + Downcast { downcast_rs::impl_downcast!(ReportingStep); -pub type ReportingStepLookupFn = fn(args: Vec) -> Box; +pub trait ReportingStepArgs: Debug + Display + Downcast + DynClone + DynEq {} + +downcast_rs::impl_downcast!(ReportingStepArgs); +dyn_clone::clone_trait_object!(ReportingStepArgs); +dyn_eq::eq_trait_object!(ReportingStepArgs); + +pub type ReportingStepLookupFn = fn(args: Box) -> Box; + +#[derive(Clone, Debug, Eq, PartialEq)] +pub struct DateArgs { + pub date: NaiveDate, +} + +impl ReportingStepArgs for DateArgs {} + +impl Display for DateArgs { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + f.write_fmt(format_args!("{}", self.date)) + } +} + +#[derive(Clone, Debug, Eq, PartialEq)] +pub struct DateEofyArgs { + pub date_eofy: NaiveDate, +} + +impl ReportingStepArgs for DateEofyArgs {} + +impl Display for DateEofyArgs { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + f.write_fmt(format_args!("{}", self.date_eofy)) + } +} + +#[derive(Clone, Debug, Eq, PartialEq)] +pub struct DateStartDateEndArgs { + pub date_start: NaiveDate, + pub date_end: NaiveDate, +} + +impl ReportingStepArgs for DateStartDateEndArgs {} + +impl Display for DateStartDateEndArgs { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + f.write_fmt(format_args!("{}, {}", self.date_start, self.date_end)) + } +} pub struct ReportingStepDynamicBuilder { name: &'static str, can_build: fn( name: &'static str, kind: ReportingProductKind, - args: Vec, + args: &Box, steps: &Vec>, dependencies: &ReportingGraphDependencies, context: &ReportingContext, @@ -153,7 +201,7 @@ pub struct ReportingStepDynamicBuilder { build: fn( name: &'static str, kind: ReportingProductKind, - args: Vec, + args: Box, steps: &Vec>, dependencies: &ReportingGraphDependencies, context: &ReportingContext, diff --git a/src/reporting/steps.rs b/src/reporting/steps.rs index 575b3e7..42a90b8 100644 --- a/src/reporting/steps.rs +++ b/src/reporting/steps.rs @@ -16,13 +16,12 @@ along with this program. If not, see . */ -use chrono::NaiveDate; - use crate::util::sofy_from_eofy; use super::{ - calculator::ReportingGraphDependencies, ReportingContext, ReportingProductId, - ReportingProductKind, ReportingStep, ReportingStepId, + calculator::ReportingGraphDependencies, DateArgs, DateEofyArgs, DateStartDateEndArgs, + ReportingContext, ReportingProductId, ReportingProductKind, ReportingStep, ReportingStepArgs, + ReportingStepId, }; pub fn register_lookup_fns(context: &mut ReportingContext) { @@ -53,15 +52,13 @@ pub fn register_lookup_fns(context: &mut ReportingContext) { #[derive(Debug)] pub struct AllTransactionsExceptRetainedEarnings { - pub date_start: NaiveDate, - pub date_end: NaiveDate, + pub args: DateStartDateEndArgs, } impl AllTransactionsExceptRetainedEarnings { - fn from_args(args: Vec) -> Box { + fn from_args(args: Box) -> Box { Box::new(AllTransactionsExceptRetainedEarnings { - date_start: NaiveDate::parse_from_str(&args[0], "%Y-%m-%d").unwrap(), - date_end: NaiveDate::parse_from_str(&args[1], "%Y-%m-%d").unwrap(), + args: *args.downcast().unwrap(), }) } } @@ -71,23 +68,20 @@ impl ReportingStep for AllTransactionsExceptRetainedEarnings { ReportingStepId { name: "AllTransactionsExceptRetainedEarnings", product_kinds: &[ReportingProductKind::BalancesBetween], - args: vec![ - self.date_start.format("%Y-%m-%d").to_string(), - self.date_end.format("%Y-%m-%d").to_string(), - ], + args: Box::new(self.args.clone()), } } } #[derive(Debug)] pub struct CalculateIncomeTax { - pub date_eofy: NaiveDate, + pub args: DateEofyArgs, } impl CalculateIncomeTax { - fn from_args(args: Vec) -> Box { + fn from_args(args: Box) -> Box { Box::new(CalculateIncomeTax { - date_eofy: NaiveDate::parse_from_str(&args[0], "%Y-%m-%d").unwrap(), + args: *args.downcast().unwrap(), }) } } @@ -97,7 +91,7 @@ impl ReportingStep for CalculateIncomeTax { ReportingStepId { name: "CalculateIncomeTax", product_kinds: &[ReportingProductKind::Transactions], - args: vec![self.date_eofy.format("%Y-%m-%d").to_string()], + args: Box::new(self.args.clone()), } } @@ -106,17 +100,16 @@ impl ReportingStep for CalculateIncomeTax { _steps: &Vec>, dependencies: &mut ReportingGraphDependencies, ) { + // CalculateIncomeTax depends on CombineOrdinaryTransactions dependencies.add_dependency( self.id(), ReportingProductId { name: "CombineOrdinaryTransactions", kind: ReportingProductKind::BalancesBetween, - args: vec![ - sofy_from_eofy(self.date_eofy) - .format("%Y-%m-%d") - .to_string(), - self.date_eofy.format("%Y-%m-%d").to_string(), - ], + args: Box::new(DateStartDateEndArgs { + date_start: sofy_from_eofy(self.args.date_eofy), + date_end: self.args.date_eofy.clone(), + }), }, ); } @@ -128,7 +121,10 @@ impl ReportingStep for CalculateIncomeTax { ) { for other in steps { if let Some(other) = other.downcast_ref::() { - if other.date_start <= self.date_eofy && other.date_end >= self.date_eofy { + if other.args.date_start <= self.args.date_eofy + && other.args.date_end >= self.args.date_eofy + { + // AllTransactionsExceptRetainedEarnings (in applicable periods) depends on CalculateIncomeTax dependencies.add_target_dependency(other.id(), self.id()); } } @@ -138,13 +134,13 @@ impl ReportingStep for CalculateIncomeTax { #[derive(Debug)] pub struct CombineOrdinaryTransactions { - pub date: NaiveDate, + pub args: DateArgs, } impl CombineOrdinaryTransactions { - fn from_args(args: Vec) -> Box { + fn from_args(args: Box) -> Box { Box::new(CombineOrdinaryTransactions { - date: NaiveDate::parse_from_str(&args[0], "%Y-%m-%d").unwrap(), + args: *args.downcast().unwrap(), }) } } @@ -154,7 +150,7 @@ impl ReportingStep for CombineOrdinaryTransactions { ReportingStepId { name: "CombineOrdinaryTransactions", product_kinds: &[ReportingProductKind::BalancesAt], - args: vec![self.date.format("%Y-%m-%d").to_string()], + args: Box::new(self.args.clone()), } } @@ -163,12 +159,13 @@ impl ReportingStep for CombineOrdinaryTransactions { _steps: &Vec>, dependencies: &mut ReportingGraphDependencies, ) { + // CombineOrdinaryTransactions depends on DBBalances dependencies.add_dependency( self.id(), ReportingProductId { name: "DBBalances", kind: ReportingProductKind::BalancesAt, - args: vec![self.date.format("%Y-%m-%d").to_string()], + args: Box::new(self.args.clone()), }, ); } @@ -176,13 +173,13 @@ impl ReportingStep for CombineOrdinaryTransactions { #[derive(Debug)] pub struct DBBalances { - pub date: NaiveDate, + pub args: DateArgs, } impl DBBalances { - fn from_args(args: Vec) -> Box { + fn from_args(args: Box) -> Box { Box::new(DBBalances { - date: NaiveDate::parse_from_str(&args[0], "%Y-%m-%d").unwrap(), + args: *args.downcast().unwrap(), }) } } @@ -192,7 +189,7 @@ impl ReportingStep for DBBalances { ReportingStepId { name: "DBBalances", product_kinds: &[ReportingProductKind::BalancesAt], - args: vec![self.date.format("%Y-%m-%d").to_string()], + args: Box::new(self.args.clone()), } } }