downsample 0.0.6

keep downsampled history of data over long period of time
Documentation
use crate::{
    Reducer,
    time_based::storage::{TimeLevel, TimeStorage, TimeWriter},
};
use alloc::vec::Vec;
use core::{marker::PhantomData, num::NonZeroUsize};

#[derive(Clone, Copy)]
struct LevelInfo<Tick, T> {
    bucket_count: NonZeroUsize,
    bucket_width: Tick,
    reducer:      Reducer<T>,
}

pub struct Builder<Tick, T> {
    raw_capacity: NonZeroUsize,
    levels:       Vec<LevelInfo<Tick, T>>,
    _data:        PhantomData<T>,
}

impl<Tick, T> Builder<Tick, T>
where
    Tick: Copy,
{
    pub fn new(raw_capacity: NonZeroUsize) -> Self {
        Self {
            raw_capacity,
            levels: Vec::new(),
            _data: PhantomData,
        }
    }

    pub fn level(mut self, bucket_count: NonZeroUsize, bucket_width: Tick, reducer: Reducer<T>) -> Self {
        self.levels.push(LevelInfo {
            bucket_count,
            bucket_width,
            reducer,
        });
        self
    }

    pub fn build(self) -> TimeWriter<Tick, T> {
        let mut levels = Vec::with_capacity(self.levels.len());
        let mut reducers = Vec::with_capacity(self.levels.len());

        for level in self.levels {
            levels.push(TimeLevel::new(level.bucket_count, level.bucket_width));
            reducers.push(level.reducer);
        }

        TimeWriter {
            storage: TimeStorage {
                data: Vec::with_capacity(self.raw_capacity.get()),
                levels,
            },
            reducers,
        }
    }
}

#[cfg(all(test, feature = "reducers"))]
mod tests {
    use super::*;
    use crate::reducers;
    use core::num::NonZeroUsize;

    const fn nz(value: usize) -> NonZeroUsize { NonZeroUsize::new(value).expect("expected non-zero value") }

    #[test]
    fn build_with_integer_ticks() {
        let writer = Builder::<u64, f32>::new(nz(128))
            .level(nz(60), 1_000_000_000, reducers::average_f32())
            .build();

        assert_eq!(writer.storage().level_count(), 1);
        assert_eq!(
            writer.storage().level_metadata(0).unwrap().bucket_width(),
            1_000_000_000
        );
    }
}