use crate::{
Reducer,
fixed_frequency::storage::{FixedStorage, FixedWriter, LevelMetadata},
};
use alloc::vec::Vec;
use core::num::NonZeroUsize;
#[derive(Clone, Copy)]
struct LevelInfo<T> {
capacity: NonZeroUsize,
aggregation_window: NonZeroUsize,
reducer: Reducer<T>,
}
pub struct Builder<T> {
raw_capacity: NonZeroUsize,
levels: Vec<LevelInfo<T>>,
}
impl<T> Builder<T> {
pub fn new(raw_capacity: NonZeroUsize) -> Self {
Self {
raw_capacity,
levels: Vec::new(),
}
}
pub fn level(mut self, capacity: NonZeroUsize, aggregation_window: NonZeroUsize, reducer: Reducer<T>) -> Self {
self.levels.push(LevelInfo {
capacity,
aggregation_window,
reducer,
});
self
}
pub fn build(self) -> FixedWriter<T>
where
T: Default,
{
let mut levels = Vec::with_capacity(self.levels.len() + 1);
let mut reducers = Vec::with_capacity(self.levels.len());
let mut start = 0;
let mut capacity = self.raw_capacity.get();
for info in self.levels {
let aggregation_window = info.aggregation_window.get();
let storage_capacity = capacity + aggregation_window;
let end = start + storage_capacity;
levels.push(LevelMetadata::new(start, end, aggregation_window));
reducers.push(info.reducer);
start = end;
capacity = info.capacity.get();
}
let end = start + capacity;
levels.push(LevelMetadata::new(start, end, 0));
let mut data = Vec::with_capacity(end);
for _ in 0..end {
data.push(T::default());
}
FixedWriter {
storage: FixedStorage { data, levels },
reducers,
}
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::reducers;
const fn nz(value: usize) -> NonZeroUsize {
match NonZeroUsize::new(value) {
Some(value) => value,
None => panic!("expected non-zero value"),
}
}
#[test]
fn construct_simple() {
let s: FixedWriter<f32> = Builder::new(nz(100))
.level(nz(59), nz(100), reducers::average_f32())
.level(nz(59), nz(60), reducers::average_f32())
.level(nz(23), nz(60), reducers::average_f32())
.build();
assert_eq!(s.storage.level_count(), 4);
let raw = s.storage.level_metadata(0).unwrap();
assert_eq!(raw.capacity(), 100);
assert_eq!(raw.aggregation_window(), 100);
assert_eq!(raw.storage_capacity(), 200);
let seconds = s.storage.level_metadata(1).unwrap();
assert_eq!(seconds.capacity(), 59);
assert_eq!(seconds.aggregation_window(), 60);
assert_eq!(seconds.storage_capacity(), 119);
let minutes = s.storage.level_metadata(2).unwrap();
assert_eq!(minutes.capacity(), 59);
assert_eq!(minutes.aggregation_window(), 60);
assert_eq!(minutes.storage_capacity(), 119);
let hours = s.storage.level_metadata(3).unwrap();
assert_eq!(hours.capacity(), 23);
assert_eq!(hours.aggregation_window(), 0);
assert_eq!(hours.storage_capacity(), 23);
}
#[test]
fn construct_use_simple() {
let mut s: FixedWriter<f32> = Builder::new(nz(100))
.level(nz(59), nz(100), reducers::average_f32())
.level(nz(59), nz(60), reducers::average_f32())
.level(nz(23), nz(60), reducers::average_f32())
.build();
for _ in 0..1000 {
s.push(0.0);
}
}
}