use generic_array::{ArrayLength, GenericArray, sequence::GenericSequence}; /// A "history buffer", similar to a write-only ring buffer of fixed length. /// /// This buffer keeps a fixed number of elements. On write, the oldest element /// is overwritten. Thus, the buffer is useful to keep a history of values with /// some desired depth, and for example calculate a rolling average. /// /// The buffer is always fully initialized; depending on the constructor, the /// initial value is either the default value for the element type or a supplied /// initial value. This simplifies the API and is mostly irrelevant for the /// intended use case. /// /// # Examples /// ``` /// use heapless::HistoryBuffer; /// use heapless::consts::*; /// /// // Initialize a new buffer with 8 elements, all initially zero. /// let mut buf = HistoryBuffer::<_, U8>::new(); /// /// buf.write(3); /// buf.write(5); /// buf.extend(&[4, 4]); /// /// // The most recent written element is a four. /// assert_eq!(buf.recent(), &4); /// /// // To access all elements in an unspecified order, use `as_slice()`. /// for el in buf.as_slice() { println!("{:?}", el); } /// /// // Now we can prepare an average of all values, which comes out to 2. /// let avg = buf.as_slice().iter().sum::() / buf.len(); /// assert_eq!(avg, 2); /// ``` #[derive(Clone)] pub struct HistoryBuffer where N: ArrayLength, { data: GenericArray, write_at: usize, } impl HistoryBuffer where N: ArrayLength, T: Default, { /// Constructs a new history buffer, where every element is filled with the /// default value of the type `T`. /// /// `HistoryBuffer` currently cannot be constructed in `const` context. /// /// # Examples /// /// ``` /// use heapless::HistoryBuffer; /// use heapless::consts::*; /// /// // Allocate a 16-element buffer on the stack /// let mut x: HistoryBuffer = HistoryBuffer::new(); /// // All elements are zero /// assert_eq!(x.as_slice(), [0; 16]); /// ``` pub fn new() -> Self { Self { data: Default::default(), write_at: 0, } } /// Clears the buffer, replacing every element with the default value of /// type `T`. pub fn clear(&mut self) { *self = Self::new(); } } impl HistoryBuffer where N: ArrayLength, T: Clone, { /// Constructs a new history buffer, where every element is the given value. /// /// # Examples /// /// ``` /// use heapless::HistoryBuffer; /// use heapless::consts::*; /// /// // Allocate a 16-element buffer on the stack /// let mut x: HistoryBuffer = HistoryBuffer::new_with(4); /// // All elements are four /// assert_eq!(x.as_slice(), [4; 16]); /// ``` pub fn new_with(t: T) -> Self { Self { data: GenericArray::generate(|_| t.clone()), write_at: 0, } } /// Clears the buffer, replacing every element with the given value. pub fn clear_with(&mut self, t: T) { *self = Self::new_with(t); } } impl HistoryBuffer where N: ArrayLength, { /// Returns the capacity of the buffer, which is the length of the /// underlying backing array. pub fn len(&self) -> usize { self.data.len() } /// Writes an element to the buffer, overwriting the oldest value. pub fn write(&mut self, t: T) { self.data[self.write_at] = t; self.write_at = (self.write_at + 1) % self.len(); } /// Clones and writes all elements in a slice to the buffer. /// /// If the slice is longer than the buffer, only the last `self.len()` /// elements will actually be stored. pub fn extend_from_slice(&mut self, other: &[T]) where T: Clone, { for item in other { self.write(item.clone()); } } /// Returns a reference to the most recently written value. /// /// # Examples /// /// ``` /// use heapless::HistoryBuffer; /// use heapless::consts::*; /// /// let mut x: HistoryBuffer = HistoryBuffer::new(); /// x.write(4); /// x.write(10); /// assert_eq!(x.recent(), &10); /// ``` pub fn recent(&self) -> &T { &self.data[(self.write_at + self.len() - 1) % self.len()] } /// Returns the array slice backing the buffer, without keeping track /// of the write position. Therefore, the element order is unspecified. pub fn as_slice(&self) -> &[T] { &self.data } } impl Extend for HistoryBuffer where N: ArrayLength, { fn extend(&mut self, iter: I) where I: IntoIterator, { for item in iter.into_iter() { self.write(item); } } } impl<'a, T, N> Extend<&'a T> for HistoryBuffer where T: 'a + Clone, N: ArrayLength, { fn extend(&mut self, iter: I) where I: IntoIterator, { self.extend(iter.into_iter().cloned()) } } #[cfg(test)] mod tests { use crate::{consts::*, HistoryBuffer}; #[test] fn new() { let x: HistoryBuffer = HistoryBuffer::new_with(1); assert_eq!(x.len(), 4); assert_eq!(x.as_slice(), [1; 4]); let x: HistoryBuffer = HistoryBuffer::new(); assert_eq!(x.as_slice(), [0; 4]); } #[test] fn write() { let mut x: HistoryBuffer = HistoryBuffer::new(); x.write(1); x.write(4); assert_eq!(x.as_slice(), [1, 4, 0, 0]); x.write(5); x.write(6); x.write(10); assert_eq!(x.as_slice(), [10, 4, 5, 6]); x.extend([11, 12].iter()); assert_eq!(x.as_slice(), [10, 11, 12, 6]); } #[test] fn clear() { let mut x: HistoryBuffer = HistoryBuffer::new_with(1); x.clear(); assert_eq!(x.as_slice(), [0; 4]); let mut x: HistoryBuffer = HistoryBuffer::new(); x.clear_with(1); assert_eq!(x.as_slice(), [1; 4]); } #[test] fn recent() { let mut x: HistoryBuffer = HistoryBuffer::new(); assert_eq!(x.recent(), &0); x.write(1); x.write(4); assert_eq!(x.recent(), &4); x.write(5); x.write(6); x.write(10); assert_eq!(x.recent(), &10); } #[test] fn as_slice() { let mut x: HistoryBuffer = HistoryBuffer::new(); x.extend([1, 2, 3, 4, 5].iter()); assert_eq!(x.as_slice(), [5, 2, 3, 4]); } }