data_frame-rs 0.1.0

Data Frame type for value over time tracking
Documentation
use std::hash::BuildHasherDefault;
use std::collections::HashMap;
use twox_hash::XxHash64;
use std::fmt::Debug;
use super::DroppedValueConsumer;


pub struct DataFrame<T, C> where C: DroppedValueConsumer<T> {
    size: usize,
    index: usize,
    items: HashMap<usize, T, BuildHasherDefault<XxHash64>>,
    consumer: C,
}

impl<T, C> DataFrame<T, C> where C: DroppedValueConsumer<T> {
    pub fn new( size: usize, consumer: C ) -> Self {
        Self {
            size,
            index: 0,
            items: HashMap::with_capacity_and_hasher(size, BuildHasherDefault::<XxHash64>::default()),
            consumer,
        }
    }
    pub fn from_frame( items: Vec<T>, consumer: C ) -> Self {
        let size = items.len();
        Self {
            size,
            index: 0,
            items: HashMap::with_capacity_and_hasher(size, BuildHasherDefault::<XxHash64>::default()),
            consumer,
        }
    }
    pub fn len( &self ) -> usize {
        self.size
    }
    fn remove_overflow( &mut self ) {
        if self.index > self.size {
            let val = self.items.remove(&(self.index - self.size));
            self.consumer.consume(val.unwrap()); 
        }
    }
    pub fn get( &self, index: usize ) -> Option<&T> {
        self.items.get(&(self.index - self.size + index + 1))
    }
    pub fn get_slice( &self ) -> Vec<Option<&T>> {
        let mut res = vec![];
        for i in (self.index - self.size + 1)..=self.index {
            res.push(self.items.get(&i));
        }
        res
    }
    pub fn add( &mut self, item: T ) {
        self.index += 1;
        self.items.insert(self.index, item);
        self.remove_overflow();
    } 
}

impl<T, C> Debug for DataFrame<T, C> where C: DroppedValueConsumer<T> + Default  {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        f.debug_struct("DataFrame").field("size", &self.size).field("index", &self.index).finish()
    }
}

#[cfg(test)]
mod test {
    use super::DataFrame;
    use crate::DefaultConsumer;

    #[test]
    pub fn test_1() {
        let mut data_frame = DataFrame::new(3, DefaultConsumer::new());
        assert_eq!(data_frame.len(), 3);
        data_frame.add(5);
        data_frame.add(4);
        data_frame.add(3);

        assert_eq!(data_frame.get_slice(), vec![Some(&5), Some(&4), Some(&3)]);

        data_frame.add(3);

        assert_eq!(data_frame.get_slice(), vec![Some(&4), Some(&3), Some(&3)]);

        data_frame.add(20);

        assert_eq!(data_frame.get(0), Some(&3));        
        assert_eq!(data_frame.get(1), Some(&3));
        assert_eq!(data_frame.get(2), Some(&20));
    }
}