rolling_buffer/buffer/
buffer.rs

1use std::cmp::min;
2
3use super::traits::Rolling;
4/// RollingBuffer is a fixed size heap buffer that will override the beginning of the buffer when it is full
5/// RollingBuffer is a very simple Vec wrapper that only uses safe code.
6/// 
7/// ['size']: size is the maximum number of elements that the buffer can hold
8/// ['vec']: vec is the underlying Vec that stores the elements of the buffer
9/// ['last_removed']: last_removed is the last element that was removed from the buffer
10/// ['count']: count is the number of elements in the buffer as if the buffer was Vec
11#[derive(Debug, Clone, Default)]
12pub struct RollingBuffer<T>
13where
14    T: Clone
15{
16    size: usize,
17    vec: Vec<T>,
18    last_removed: Option<T>,
19    count: usize,
20}
21
22
23impl<T> Rolling<T> for RollingBuffer<T> 
24where
25    T: Clone + Default
26{
27    /// Creates a new RollingBuffer with the given size and initial value (aka none)
28    /// If the size is 0, the buffer will behave as a normal Vec
29    fn new(size: usize) -> Self {
30        Self {
31            size,
32            vec: if size > 0 {
33                vec![T::default(); size]
34            } else {
35                Vec::new()
36            },
37            last_removed: None,
38            count: 0,
39        }
40    }
41
42    
43    /// Adds an element to the buffer, overriding the beginning of the buffer when it is full
44    /// Here using "safe code", but it is essentially unsafe ptr::write()
45    fn push(&mut self, value: T) {
46        if self.size > 0 {
47            let index = self.count as usize % self.size;
48            self.last_removed = Some(std::mem::replace(&mut self.vec[index], value));
49        } else {
50            self.vec.push(value);
51        }
52        self.count += 1;
53    }
54
55    
56    /// Get the element at the given index, as if the buffer was a Vec
57    /// 
58    /// buffer of size 3, adding 1,2,3,4 and asking for the element at index 3 will return 4.
59    /// Asking for index 0 will return None
60    /// since this element was overriden already.
61    /// Example:
62    /// ```
63    /// let mut buffer = RollingBuffer::<i32>::new(3, 0);
64    /// buffer.push(1);
65    /// buffer.push(2);
66    /// buffer.push(3);
67    /// buffer.push(4);
68    /// assert_eq!(buffer.get(3), Some(&4));
69    /// assert_eq!(buffer.get(0), None);
70    /// ```
71    fn get(&self, i: usize) -> Option<&T> {
72        if self.size > 0 {
73            Some(&self.vec[i % self.size])
74        } else if i < self.vec.len() {
75            Some(&self.vec[i])
76        } else {
77            None
78        }
79    }
80
81    /// Returns an option containing a reference to the first element in the rolling data.
82    ///
83    /// If no elements have been added (`count` is zero), it returns `None`.
84    /// Otherwise, it returns a reference to the last added element.
85    /// The index calculation considers the possibility of wrapping around when
86    /// the number of elements added exceeds the size of the vec.
87    fn last(&self) -> Option<&T> {
88        if self.count == 0 {
89            None
90        } else if self.size > 0 {
91            let index = (self.count as usize - 1) % self.size;
92            Some(&self.vec[index])
93        } else {
94            Some(&self.vec[self.vec.len() - 1])
95        }
96    }
97
98    /// Last added element's mutable reference.
99    fn last_mut(&mut self) -> Option<&mut T> {
100        if self.count == 0 {
101            None
102        } else if self.size > 0 {
103            let index = (self.count as usize - 1) % self.size;
104            Some(&mut self.vec[index])
105        } else {
106            let index = self.vec.len() - 1;
107            Some(&mut self.vec[index])
108        }
109    }
110
111    /// Returns the theoretical first element.
112    /// 
113    /// Example: 
114    /// ```
115    /// let mut buffer = RollingBuffer::<i32>::new(3);
116    /// buffer.push(1);
117    /// buffer.push(2);
118    /// buffer.push(3);
119    /// buffer.push(4);
120    /// assert_eq!(buffer.first(), Some(&2));
121    /// ```
122    fn first(&self) -> Option<&T> {
123        if self.count == 0 {
124            None
125        } else if self.size > 0 {
126            if self.count <= self.size {
127                Some(&self.vec[0])
128            } else {
129                let index = (self.count as usize) % self.size;
130                Some(&self.vec[index])
131            }
132        } else {
133            Some(&self.vec[0])
134        }
135    }
136
137    /// Returns theoretical len as if it was a Vec.
138    fn len(&self) -> usize {
139        if self.count < self.size {
140            self.count as usize
141        } else {
142            self.vec.len()
143        }
144    }
145
146    /// Returns the maximum number of elements that can be stored.
147    fn size(&self) -> usize {
148        self.size
149    }
150
151    /// Returns the underlying vector as it is stored inside the RollingBuffer.
152    fn raw(&self) -> &Vec<T> {
153        &self.vec
154    }
155
156    /// Returns the last removed element. Can be very useful if needed for debugging or other purposes.
157    fn last_removed(&self) -> &Option<T> {
158        &self.last_removed
159    }
160 
161    /// Returns 'expected' number of elements as if the RollingBuffer was a Vec.
162    /// i.e. the number of elements that would be in the Vec if it was not a RollingBuffer.
163    fn count(&self) -> usize {
164        self.count as usize
165    }
166
167    /// Returns true if the RollingBuffer is empty.
168    fn is_empty(&self) -> bool {
169        self.count == 0
170    }
171    
172    /// Creates a new Vec, which contains all elements in the RollingBuffer in correct order.
173    fn to_vec(&self) -> Vec<T> {
174        if self.size > 0 {
175            let start = if self.count <= self.size {
176                0 as usize
177            } else {
178                self.count % self.size
179            };
180            let mut vec = Vec::<T>::new();
181            for i in start..start + min(self.size, self.count) {
182                vec.push(self.vec[i % self.size].clone());
183            }
184            vec
185        } else {
186            self.vec.clone()
187        }
188    }
189}