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}