use crate::circular_buffer::SerdeCircularBuffer;
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 + Clone,
{
pub recent: SerdeCircularBuffer<N_MOST_RECENT, T>,
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 + Clone,
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 + Clone,
{
pub fn push_in_cum_type(&mut self, val: CUM) {
let as_buf = T::from(val.clone());
self.recent.push_back(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_back(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 + Clone,
{
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 + Clone,
{
pub fn extend(&mut self, rhs: History<T, CUM, N>) {
self.total_historic = self.total_historic.clone() + rhs.total_historic.clone();
self.total_tests += rhs.total_tests;
self.recent.0.extend(rhs.recent.0);
}
pub fn extended(mut self, rhs: History<T, CUM, N>) -> History<T, CUM, N> {
self.extend(rhs);
self
}
#[inline]
pub fn most_recent(&self) -> Option<&T> {
self.recent.nth_back(0)
}
#[inline]
pub fn previous(&self) -> Option<&T> {
self.recent.nth_back(1)
}
#[inline]
pub fn n_ago(&self, n: usize) -> Option<&T> {
self.recent.nth_back(n)
}
}
#[cfg(test)]
mod test {
use super::History;
#[test]
fn push() {
let mut s = History::<u32, u64, 2>::new();
assert_eq!(s.most_recent(), None);
assert_eq!(s.total_tests, 0);
assert_eq!(s.total_historic, 0);
s.push(100);
assert_eq!(s.most_recent().unwrap(), &100);
assert_eq!(s.total_tests, 1);
assert_eq!(s.total_historic, 100);
s.push(101);
assert_eq!(s.most_recent().unwrap(), &101);
assert_eq!(s.previous().unwrap(), &100);
assert_eq!(s.total_tests, 2);
assert_eq!(s.total_historic, 201);
s.push(102);
assert_eq!(s.most_recent().unwrap(), &102);
assert_eq!(s.previous().unwrap(), &101);
assert_eq!(s.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.extended(newer);
assert_eq!(appended.n_ago(0).unwrap(), &104);
assert_eq!(appended.n_ago(1).unwrap(), &103);
assert_eq!(appended.n_ago(2).unwrap(), &102);
assert_eq!(appended.n_ago(3).unwrap(), &101);
assert_eq!(appended.n_ago(4).unwrap(), &100);
assert_eq!(appended.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.extended(newer);
assert_eq!(appended.n_ago(0).unwrap(), &104);
assert_eq!(appended.n_ago(1).unwrap(), &103);
assert_eq!(appended.n_ago(2).unwrap(), &102);
assert_eq!(appended.total_historic, older_cum + newer_cum);
assert_eq!(appended.total_tests, older_tests + newer_tests);
}
}