aboutsummaryrefslogtreecommitdiff
path: root/src/ring_buffer.rs
blob: b523c9ae1c9b567756771322d61ca545412d011e (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
use std::fmt::{Display, Formatter};
use std::error::Error;
use std::ops::{Index, IndexMut};
use std::borrow::Borrow;
use std::iter::Iterator;

pub struct RingBuffer<T, const SIZE : usize>
{
    //storage is an array, because arrays _guarantee_ an initialized fixed size.
    //It's inside a box, because that way we can collect() into it without copying from heap to
    //stack.
    storage : Box<[T;SIZE]>,
    index : usize,
}

#[derive(Debug)]
pub struct RingBufferInitError;
impl Display for RingBufferInitError {
    fn fmt(&self, f: &mut Formatter) -> Result<(), std::fmt::Error> {
        write!(f,"Not enough input to initialize the ring buffer")
    }
}
impl Error for RingBufferInitError {}

impl<T, const SIZE : usize> RingBuffer<T, SIZE> 
{
    pub fn push_pop(mut self,new_entry : T) -> (Self, T) {
        let old_value = std::mem::replace(&mut self.storage[self.index], new_entry);
        self.index = (self.index + 1) % SIZE;
        (self, old_value)
    }

    pub fn new<I>(mut input : I) -> Result<(Self,I), RingBufferInitError>
        where I : Iterator<Item=T>
    {
        let slice = input.by_ref().take(SIZE).collect::<Box<[T]>>();
        let array = slice.try_into().map_err(|_| RingBufferInitError)?;
        Ok((RingBuffer { storage : array, index : 0 },input))
    }

    pub fn new_init(init : T) -> Self 
        where T : Copy 
    {
        RingBuffer { storage : Box::new([init;SIZE]), index : 0 }
    }

    pub fn get(&self, index : usize) -> Option<&T> {
        if index >= SIZE {
            None
        }
        else {
            Some(&self.storage[self.get_arr_index_wrapped(index)])
        }
    }

    pub fn get_mut(&mut self, index: usize) -> Option<&mut T> {
        if index >= SIZE {
            None
        }
        else {
            Some(&mut self.storage[self.get_arr_index_wrapped(index)])
        }
    }

    pub fn iter(&self) -> RingBufferIterator<T,SIZE> {
        RingBufferIterator { ring_buffer : self, index : 0 }
    }

    fn get_arr_index_wrapped(&self, index : usize) -> usize {
        (self.index + index) % SIZE
    }
}

impl<T, const SIZE :usize> Index<usize> for RingBuffer<T, SIZE> {
    type Output = T;
    fn index(&self, index : usize) -> &T {
        self.get(index).expect("Ring buffer index out of bounds")
    }
}

impl<T, const SIZE : usize> IndexMut<usize> for RingBuffer<T, SIZE> {
    fn index_mut(&mut self, index :usize) -> &mut T {
        self.get_mut(index).expect("Ring buffer index out of bounds")
    }
}

pub struct RingBufferIterator<'a, T, const SIZE :usize> {
    ring_buffer : &'a RingBuffer<T, SIZE>,
    index : usize,
}

impl<'b, T, const SIZE : usize> Iterator for RingBufferIterator<'b, T, SIZE> {
    type Item = &'b T;
    fn next(&mut self) -> Option<&'b T> {
        let result = self.ring_buffer.get(self.index);
        if result.is_some() {
            self.index += 1;
        }
        result
    }
}

impl<T, const SIZE : usize> IntoIterator for RingBuffer<T, SIZE> {
    type Item = T;
    type IntoIter = std::collections::vec_deque::IntoIter<T>;
    fn into_iter(self) -> Self::IntoIter {
        let slice = self.storage as Box<[T]>;
        let vec : Vec<T> = slice.into();
        let mut deque : std::collections::VecDeque<T> = vec.into();
        deque.rotate_left(self.index);
        deque.into_iter()
    }
}

impl<'b, T, const SIZE : usize> IntoIterator for &'b RingBuffer<T, SIZE> {
    type Item = &'b T;
    type IntoIter = RingBufferIterator<'b, T, SIZE>;
    fn into_iter(self) -> Self::IntoIter {
        self.iter()
    }
}