diff options
Diffstat (limited to 'src/lib.rs')
-rw-r--r-- | src/lib.rs | 99 |
1 files changed, 80 insertions, 19 deletions
@@ -22,16 +22,16 @@ impl AddAssign for Capital { } } -pub struct Simulation { +pub struct Simulation<'a> { st: SimState, - updates: SimUpdates, + updates: SimUpdates<'a>, history: Vec<Quota>, topay: Capital, payed: Capital, payed_amortized: f64, } -impl Simulation { +impl<'a> Simulation<'a> { pub fn new(principal: f64, i1: f64, years: u32) -> Self { let pending_quotas = years * 12; let i12 = i1 / 12.0; @@ -59,11 +59,11 @@ impl Simulation { }, payed_amortized: 0., history: vec![], - updates: HashMap::new(), + updates: SimUpdates::new(), } } - pub fn run(&mut self, updates: SimUpdates) { + pub fn run(&mut self, updates: SimUpdates<'a>) { self.updates = updates; let mut st = self.st.clone(); while st.pending_quotas > 0 && st.principal > 0. { @@ -75,17 +75,18 @@ impl Simulation { } fn apply_updates(&mut self, st: &mut SimState) { - match self.updates.get_mut(&st.period) { - Some(SimUpdate::Amortize(principal)) => { - if *principal > st.principal { - *principal = st.principal; - }; - st.principal -= *principal; - st.calculate_monthly(); - self.payed.principal += *principal; - self.payed_amortized += *principal; + for update in self.updates.get(st.period) { + match update { + SimUpdate::Amortize(mut principal) => { + if principal > st.principal { + principal = st.principal; + }; + st.principal -= principal; + st.calculate_monthly(); + self.payed.principal += principal; + self.payed_amortized += principal; + } } - None => (), } } @@ -105,7 +106,7 @@ impl Simulation { println!("Year | Mon | Quota ( Amrtzd + Intrst) | Pending"); for st in self.history.iter() { print!("{st}"); - if let Some(update) = self.updates.get(&st.period) { + for update in self.updates.get(st.period) { print!(" {update}"); } println!(); @@ -205,9 +206,55 @@ impl fmt::Display for Quota { } } -pub type SimUpdates = HashMap<u32, SimUpdate>; +#[derive(Debug)] +pub struct SimUpdates<'a> { + periodically: Vec<(u32, Vec<&'a SimUpdate>)>, + by_month: HashMap<u32, Vec<&'a SimUpdate>>, +} +// pub type SimUpdates<'a> = HashMap<u32, &'a SimUpdate>; +impl<'a> SimUpdates<'a> { + pub fn new() -> Self { + SimUpdates { + periodically: vec![], + by_month: HashMap::new(), + } + } -#[derive(Clone)] + fn get(&self, month: u32) -> Vec<&'a SimUpdate> { + let SimUpdates { + periodically, + by_month, + } = self; + + let mut ret = vec![]; + for (m, updates) in periodically.iter() { + if month % m == 0 { + for update in updates.iter() { + ret.push(*update); + } + } + } + if let Some(updates) = by_month.get(&month) { + for update in updates.iter() { + ret.push(*update); + } + } + // println!(" {self:?}.get({month}) -> {ret:?}"); + ret + } + + pub fn and(mut self, other: SimUpdates<'a>) -> Self { + for p in other.periodically.iter() { + self.periodically.push(p.clone()); + } + for (k, v) in other.by_month { + self.by_month.insert(k, v); + } + self + } +} + +#[derive(Clone, Debug)] pub enum SimUpdate { Amortize(f64), } @@ -217,8 +264,22 @@ impl fmt::Display for SimUpdate { write!(f, "[MORTGAGE UPDATE: ")?; match self { Self::Amortize(principal) => { - write!(f, "{principal:.2} amortized to reduce pending_quotas]") + write!(f, "{principal:.2} amortized to reduce pending quotas]") } } } } + +impl SimUpdate { + pub fn every(&self, months: u32) -> SimUpdates { + let mut updates = SimUpdates::new(); + updates.periodically.push((months, vec![self])); + updates + } + + pub fn at(&self, month: u32) -> SimUpdates { + let mut updates = SimUpdates::new(); + updates.by_month.insert(month, vec![self]); + updates + } +} |