Refactor representation of ReportingStep args

This commit is contained in:
RunasSudo 2025-05-21 16:39:18 +10:00
parent f15d190112
commit a7e9c74dd1
Signed by: RunasSudo
GPG Key ID: 7234E476BF21C61A
7 changed files with 140 additions and 76 deletions

14
Cargo.lock generated
View File

@ -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",
]

View File

@ -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"

View File

@ -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<Box<dyn ReportingStep>> = 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),
}
}

View File

@ -16,12 +16,10 @@
along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
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<String>,
args: &Box<dyn ReportingStepArgs>,
steps: &Vec<Box<dyn ReportingStep>>,
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<String>,
args: Box<dyn ReportingStepArgs>,
_steps: &Vec<Box<dyn ReportingStep>>,
_dependencies: &ReportingGraphDependencies,
_context: &ReportingContext,
) -> Box<dyn ReportingStep> {
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<Box<dyn ReportingStep>>,
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<String>,
_args: &Box<dyn ReportingStepArgs>,
steps: &Vec<Box<dyn ReportingStep>>,
dependencies: &ReportingGraphDependencies,
_context: &ReportingContext,
@ -191,15 +188,14 @@ impl UpdateBalancesBetween {
fn build(
name: &'static str,
_kind: ReportingProductKind,
args: Vec<String>,
args: Box<dyn ReportingStepArgs>,
_steps: &Vec<Box<dyn ReportingStep>>,
_dependencies: &ReportingGraphDependencies,
_context: &ReportingContext,
) -> Box<dyn ReportingStep> {
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()),
}
}

View File

@ -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,

View File

@ -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<String>,
args: Box<dyn ReportingStepArgs>,
}
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<String>,
pub args: Box<dyn ReportingStepArgs>,
}
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<String>) -> Box<dyn ReportingStep>;
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<dyn ReportingStepArgs>) -> Box<dyn ReportingStep>;
#[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<String>,
args: &Box<dyn ReportingStepArgs>,
steps: &Vec<Box<dyn ReportingStep>>,
dependencies: &ReportingGraphDependencies,
context: &ReportingContext,
@ -153,7 +201,7 @@ pub struct ReportingStepDynamicBuilder {
build: fn(
name: &'static str,
kind: ReportingProductKind,
args: Vec<String>,
args: Box<dyn ReportingStepArgs>,
steps: &Vec<Box<dyn ReportingStep>>,
dependencies: &ReportingGraphDependencies,
context: &ReportingContext,

View File

@ -16,13 +16,12 @@
along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
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<String>) -> Box<dyn ReportingStep> {
fn from_args(args: Box<dyn ReportingStepArgs>) -> Box<dyn ReportingStep> {
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<String>) -> Box<dyn ReportingStep> {
fn from_args(args: Box<dyn ReportingStepArgs>) -> Box<dyn ReportingStep> {
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<Box<dyn ReportingStep>>,
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::<AllTransactionsExceptRetainedEarnings>() {
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<String>) -> Box<dyn ReportingStep> {
fn from_args(args: Box<dyn ReportingStepArgs>) -> Box<dyn ReportingStep> {
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<Box<dyn ReportingStep>>,
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<String>) -> Box<dyn ReportingStep> {
fn from_args(args: Box<dyn ReportingStepArgs>) -> Box<dyn ReportingStep> {
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()),
}
}
}