use brk_error::Result;
use brk_traversable::Traversable;
use brk_types::{Height, Version};
use schemars::JsonSchema;
use vecdb::{
AnyStoredVec, AnyVec, CachedBoxedVec, Database, ReadOnlyClone, ReadableVec, Rw, StorageMode,
WritableVec,
};
use super::lazy_cumulative_rolling::lazy_parts;
use crate::{
indexes,
internal::{
CachedPerBlock, CachedWindowStartVec, LazyPreviousDeltaVec, LazyRollingAvgsFromHeight,
LazyRollingSumsFromHeight, NumericValue, Windows,
},
};
#[derive(Traversable)]
pub struct CachedPerBlockCumulativeRolling<T, M: StorageMode = Rw>
where
T: NumericValue + JsonSchema,
{
pub block: LazyPreviousDeltaVec<Height, T>,
pub cumulative: CachedPerBlock<T, M>,
pub sum: LazyRollingSumsFromHeight<T>,
pub average: LazyRollingAvgsFromHeight<T>,
#[traversable(skip)]
last_cumulative: Option<(usize, T)>,
}
impl<T> CachedPerBlockCumulativeRolling<T>
where
T: NumericValue + JsonSchema,
{
pub(crate) fn forced_import(
db: &Database,
name: &str,
version: Version,
indexes: &indexes::Vecs,
cached_starts: &Windows<&CachedWindowStartVec>,
) -> Result<Self> {
let cumulative =
CachedPerBlock::forced_import(db, &format!("{name}_cumulative"), version, indexes)?;
let cumulative_source = cumulative.height.read_only_clone();
let (block, sum, average) =
lazy_parts(name, version, &cumulative_source, cached_starts, indexes);
let last_cumulative = cumulative
.height
.collect_last()
.map(|value| (cumulative.height.len(), value));
Ok(Self {
block,
cumulative,
sum,
average,
last_cumulative,
})
}
pub(crate) fn cached_cumulative(&self) -> CachedBoxedVec<Height, T> {
self.cumulative.height.read_only_cached_boxed_clone()
}
#[inline(always)]
pub(crate) fn push_block(&mut self, value: T)
where
T: Copy,
{
let len = self.cumulative.height.len();
let mut cumulative = match self.last_cumulative {
Some((cached_len, value)) if cached_len == len => value,
_ => self.cumulative.height.collect_last().unwrap_or_default(),
};
cumulative += value;
self.cumulative.height.inner.push(cumulative);
self.last_cumulative = Some((len + 1, cumulative));
}
pub(crate) fn validate_and_truncate(&mut self, version: Version, height: Height) -> Result<()> {
self.cumulative
.height
.inner
.validate_and_truncate(version, height)?;
Ok(())
}
pub(crate) fn truncate_if_needed_at(&mut self, len: usize) -> Result<()> {
self.cumulative.height.inner.truncate_if_needed_at(len)?;
Ok(())
}
pub(crate) fn write(&mut self) -> Result<()> {
self.cumulative.height.inner.write()?;
Ok(())
}
}