use crate::RunningBuffer;
use core::clone::Clone;
use core::default::Default;
use core::ops::Add;
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[derive(Clone, Debug)]
pub struct History<T, CUM, const N_MOST_RECENT: usize>
where
T: Default,
{
pub recent: RunningBuffer<T, N_MOST_RECENT>,
total_historic: CUM,
total_tests: u32,
}
impl<T, CUM, const N_MOST_RECENT: usize> Default for History<T, CUM, N_MOST_RECENT>
where
T: Default,
CUM: Default,
{
fn default() -> Self {
Self {
recent: Default::default(),
total_historic: Default::default(),
total_tests: Default::default(),
}
}
}
impl<T, CUM, const N_MOST_RECENT: usize> History<T, CUM, N_MOST_RECENT>
where
CUM: Clone + Add<Output = CUM>,
T: From<CUM> + Default,
{
pub fn push_in_cum_type(&mut self, val: CUM) {
let as_buf = T::from(val.clone());
self.recent.push(as_buf);
self.total_tests += 1;
let prev_sum = self.total_historic.clone();
self.total_historic = prev_sum + val;
}
}
impl<T, CUM, const N_MOST_RECENT: usize> History<T, CUM, N_MOST_RECENT>
where
CUM: Clone + Add<Output = CUM> + From<T>,
T: Clone + Default,
{
pub fn push(&mut self, val: T) {
let as_cum = CUM::from(val.clone());
self.recent.push(val);
self.total_tests += 1;
let prev_sum = self.total_historic.clone();
self.total_historic = prev_sum + as_cum;
}
pub fn pushed(mut self, val: T) -> Self {
self.push(val);
self
}
}
impl<T, CUM, const N: usize> History<T, CUM, N>
where
CUM: Default,
T: Default,
{
pub fn new() -> History<T, CUM, N> {
History {
recent: Default::default(),
total_historic: Default::default(),
total_tests: 0,
}
}
}
impl<T, CUM, const N: usize> History<T, CUM, N>
where
CUM: Clone + Add<Output = CUM>,
T: Default,
{
pub fn joined(self, rhs: History<T, CUM, N>) -> History<T, CUM, N> {
let total_historic = self.total_historic + rhs.total_historic;
let total_tests = self.total_tests + rhs.total_tests;
let older_count = self.recent.amount_of_entries() as usize;
let rhs_count = rhs.recent.amount_of_entries() as usize;
let mut lhs = self.recent.as_array();
let mut newer = rhs.recent.as_array();
let leftover = N.saturating_sub(rhs_count);
let to_keep = leftover.min(older_count);
lhs.rotate_right(rhs_count);
for i in 0..rhs_count {
core::mem::swap(&mut lhs[i], &mut newer[i]);
}
let n_entries = core::cmp::min(rhs_count + to_keep, N) as u16;
Self {
recent: RunningBuffer::new_unchecked(lhs, n_entries),
total_historic,
total_tests,
}
}
}
#[cfg(test)]
mod test {
use super::History;
#[test]
fn push() {
let mut s = History::<u32, u64, 2>::new();
assert_eq!(s.recent.n_ago(0), None);
assert_eq!(s.total_tests, 0);
assert_eq!(s.total_historic, 0);
s.push(100);
assert_eq!(s.recent.n_ago(0).unwrap(), &100);
assert_eq!(s.total_tests, 1);
assert_eq!(s.total_historic, 100);
s.push(101);
assert_eq!(s.recent.n_ago(0).unwrap(), &101);
assert_eq!(s.recent.n_ago(1).unwrap(), &100);
assert_eq!(s.total_tests, 2);
assert_eq!(s.total_historic, 201);
s.push(102);
assert_eq!(s.recent.n_ago(0).unwrap(), &102);
assert_eq!(s.recent.n_ago(1).unwrap(), &101);
assert_eq!(s.recent.n_ago(2), None);
assert_eq!(s.total_tests, 3);
assert_eq!(s.total_historic, 303);
}
#[test]
fn joined() {
let older = History::<u32, u64, 6>::new()
.pushed(100)
.pushed(101)
.pushed(102);
let newer = History::<u32, u64, 6>::new().pushed(103).pushed(104);
let appended = older.joined(newer);
let series = appended.clone().recent;
assert_eq!(series.n_ago(0).unwrap(), &104);
assert_eq!(series.n_ago(1).unwrap(), &103);
assert_eq!(series.n_ago(2).unwrap(), &102);
assert_eq!(series.n_ago(3).unwrap(), &101);
assert_eq!(series.n_ago(4).unwrap(), &100);
assert_eq!(series.n_ago(5), None);
let older = History::<u32, u64, 3>::new()
.pushed(100)
.pushed(101)
.pushed(102);
let older_cum = older.total_historic;
let older_tests = older.total_tests;
let newer = History::<u32, u64, 3>::new().pushed(103).pushed(104);
let newer_cum = newer.total_historic;
let newer_tests = newer.total_tests;
let appended = older.joined(newer);
let series = appended.clone().recent;
assert_eq!(series.n_ago(0).unwrap(), &104);
assert_eq!(series.n_ago(1).unwrap(), &103);
assert_eq!(series.n_ago(2).unwrap(), &102);
assert_eq!(appended.total_historic, older_cum + newer_cum);
assert_eq!(appended.total_tests, older_tests + newer_tests);
}
}