From 35a3e6b0a4e6e1dbaf9f4c0d2ce0784f14dcccec Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sosth=C3=A8ne=20Gu=C3=A9don?= Date: Thu, 27 Jun 2024 09:46:13 +0200 Subject: [PATCH 1/4] Implement HistoryBufferView --- src/histbuf.rs | 409 +++++++++++++++++++++++++++++++++++++++++++++++-- src/lib.rs | 2 +- 2 files changed, 396 insertions(+), 15 deletions(-) diff --git a/src/histbuf.rs b/src/histbuf.rs index 98f7556181..e680749195 100644 --- a/src/histbuf.rs +++ b/src/histbuf.rs @@ -4,6 +4,40 @@ use core::ops::Deref; use core::ptr; use core::slice; +pub struct HistoryBufferInner { + write_at: usize, + filled: bool, + data: B, +} + +///
This is private API and should not be used
+pub trait HistBuffer { + type T; + + fn as_hist_view(this: &HistoryBufferInner) -> &HistoryBufferView; + fn as_mut_hist_view(this: &mut HistoryBufferInner) -> &mut HistoryBufferView; +} + +impl HistBuffer for [MaybeUninit; N] { + type T = T; + fn as_hist_view(this: &HistoryBufferInner) -> &HistoryBufferView { + this + } + fn as_mut_hist_view(this: &mut HistoryBufferInner) -> &mut HistoryBufferView { + this + } +} + +impl HistBuffer for [MaybeUninit] { + type T = T; + fn as_hist_view(this: &HistoryBufferInner) -> &HistoryBufferView { + this + } + fn as_mut_hist_view(this: &mut HistoryBufferInner) -> &mut HistoryBufferView { + this + } +} + /// 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 @@ -36,11 +70,42 @@ use core::slice; /// let avg = buf.as_slice().iter().sum::() / buf.len(); /// assert_eq!(avg, 4); /// ``` -pub struct HistoryBuffer { - data: [MaybeUninit; N], - write_at: usize, - filled: bool, -} +pub type HistoryBuffer = HistoryBufferInner<[MaybeUninit; N]>; + +/// 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. +/// +/// # Examples +/// ``` +/// use heapless::HistoryBuffer; +/// +/// // Initialize a new buffer with 8 elements. +/// let mut buf = HistoryBuffer::<_, 8>::new(); +/// let buf_view: &mut HistoryBufferView<_> = &mut buf; +/// +/// // Starts with no data +/// assert_eq!(buf.recent(), None); +/// +/// buf.write(3); +/// buf.write(5); +/// buf.extend(&[4, 4]); +/// +/// // The most recent written element is a four. +/// assert_eq!(buf.recent(), Some(&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 4. +/// let avg = buf.as_slice().iter().sum::() / buf.len(); +/// assert_eq!(avg, 4); +/// ``` +pub type HistoryBufferView = HistoryBufferInner<[MaybeUninit]>; impl HistoryBuffer { const INIT: MaybeUninit = MaybeUninit::uninit(); @@ -73,7 +138,63 @@ impl HistoryBuffer { /// Clears the buffer, replacing every element with the default value of /// type `T`. pub fn clear(&mut self) { - *self = Self::new(); + self.as_mut_view().clear(); + } + + pub fn as_view(&self) -> &HistoryBufferView { + self + } + + pub fn as_mut_view(&mut self) -> &mut HistoryBufferView { + self + } +} + +impl HistoryBufferView { + fn drop_impl(&mut self) { + unsafe { + ptr::drop_in_place(ptr::slice_from_raw_parts_mut( + self.data.as_mut_ptr() as *mut T, + self.len(), + )) + } + } + + /// Clears the buffer, replacing every element with the default value of + /// type `T`. + pub fn clear(&mut self) { + // Drop all current stored values + self.drop_impl(); + let Self { + // Data is all MaybeUninit, we don't need to reset it + data: _, + write_at, + filled, + } = self; + *write_at = 0; + *filled = false; + } +} + +impl HistoryBufferView +where + T: Copy, +{ + /// Clears the buffer, replacing every element with the given value. + pub fn clear_with(&mut self, t: T) { + // Drop all current stored values + self.drop_impl(); + let Self { + // Data is all MaybeUninit, we don't need to reset it + data, + write_at, + filled, + } = self; + *write_at = 0; + *filled = true; + for slot in data { + *slot = MaybeUninit::new(t); + } } } @@ -104,7 +225,200 @@ where /// Clears the buffer, replacing every element with the given value. pub fn clear_with(&mut self, t: T) { - *self = Self::new_with(t); + self.as_mut_view().clear_with(t) + } +} +impl HistoryBufferView { + /// Returns the current fill level of the buffer. + #[inline] + pub fn len(&self) -> usize { + if self.filled { + self.data.len() + } else { + self.write_at + } + } + /// Returns true if the buffer is empty. + /// + /// # Examples + /// + /// ``` + /// use heapless::HistoryBuffer; + /// + /// let x: HistoryBuffer = HistoryBuffer::new(); + /// assert!(x.is_empty()); + /// ``` + #[inline] + pub fn is_empty(&self) -> bool { + self.len() == 0 + } + + /// Returns the capacity of the buffer, which is the length of the + /// underlying backing array. + #[inline] + pub fn capacity(&self) -> usize { + self.data.len() + } + + /// Returns whether the buffer is full + #[inline] + pub fn is_full(&self) -> bool { + self.filled + } + + /// Writes an element to the buffer, overwriting the oldest value. + pub fn write(&mut self, t: T) { + if self.filled { + // Drop the old before we overwrite it. + unsafe { ptr::drop_in_place(self.data[self.write_at].as_mut_ptr()) } + } + self.data[self.write_at] = MaybeUninit::new(t); + + self.write_at += 1; + if self.write_at == self.capacity() { + self.write_at = 0; + self.filled = true; + } + } + + /// 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; + /// + /// let mut x: HistoryBuffer = HistoryBuffer::new(); + /// x.write(4); + /// x.write(10); + /// assert_eq!(x.recent(), Some(&10)); + /// ``` + pub fn recent(&self) -> Option<&T> { + self.recent_index() + .map(|i| unsafe { &*self.data[i].as_ptr() }) + } + + /// Returns index of the most recently written value in the underlying slice. + /// + /// # Examples + /// + /// ``` + /// use heapless::HistoryBuffer; + /// + /// let mut x: HistoryBuffer = HistoryBuffer::new(); + /// x.write(4); + /// x.write(10); + /// assert_eq!(x.recent_index(), Some(1)); + /// ``` + pub fn recent_index(&self) -> Option { + if self.write_at == 0 { + if self.filled { + Some(self.capacity() - 1) + } else { + None + } + } else { + Some(self.write_at - 1) + } + } + + /// Returns a reference to the oldest value in the buffer. + /// + /// # Examples + /// + /// ``` + /// use heapless::HistoryBuffer; + /// + /// let mut x: HistoryBuffer = HistoryBuffer::new(); + /// x.write(4); + /// x.write(10); + /// assert_eq!(x.oldest(), Some(&4)); + /// ``` + pub fn oldest(&self) -> Option<&T> { + self.oldest_index() + .map(|i| unsafe { &*self.data[i].as_ptr() }) + } + + /// Returns index of the oldest value in the underlying slice. + /// + /// # Examples + /// + /// ``` + /// use heapless::HistoryBuffer; + /// + /// let mut x: HistoryBuffer = HistoryBuffer::new(); + /// x.write(4); + /// x.write(10); + /// assert_eq!(x.oldest_index(), Some(0)); + /// ``` + pub fn oldest_index(&self) -> Option { + if self.filled { + Some(self.write_at) + } else if self.write_at == 0 { + None + } else { + Some(0) + } + } + + /// 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] { + unsafe { slice::from_raw_parts(self.data.as_ptr() as *const _, self.len()) } + } + + /// Returns a pair of slices which contain, in order, the contents of the buffer. + /// + /// # Examples + /// + /// ``` + /// use heapless::HistoryBuffer; + /// + /// let mut buffer: HistoryBuffer = HistoryBuffer::new(); + /// buffer.extend([0, 0, 0]); + /// buffer.extend([1, 2, 3, 4, 5, 6]); + /// assert_eq!(buffer.as_slices(), (&[1, 2, 3][..], &[4, 5, 6][..])); + /// ``` + pub fn as_slices(&self) -> (&[T], &[T]) { + let buffer = self.as_slice(); + + if !self.filled { + (buffer, &[]) + } else { + (&buffer[self.write_at..], &buffer[..self.write_at]) + } + } + + /// Returns an iterator for iterating over the buffer from oldest to newest. + /// + /// # Examples + /// + /// ``` + /// use heapless::HistoryBuffer; + /// + /// let mut buffer: HistoryBuffer = HistoryBuffer::new(); + /// buffer.extend([0, 0, 0, 1, 2, 3, 4, 5, 6]); + /// let expected = [1, 2, 3, 4, 5, 6]; + /// for (x, y) in buffer.oldest_ordered().zip(expected.iter()) { + /// assert_eq!(x, y) + /// } + /// ``` + pub fn oldest_ordered(&self) -> impl Iterator { + let (old, new) = self.as_slices(); + old.iter().chain(new) } } @@ -316,6 +630,15 @@ impl HistoryBuffer { } impl Extend for HistoryBuffer { + fn extend(&mut self, iter: I) + where + I: IntoIterator, + { + self.as_mut_view().extend(iter) + } +} + +impl Extend for HistoryBufferView { fn extend(&mut self, iter: I) where I: IntoIterator, @@ -327,6 +650,18 @@ impl Extend for HistoryBuffer { } impl<'a, T, const N: usize> Extend<&'a T> for HistoryBuffer +where + T: 'a + Clone, +{ + fn extend(&mut self, iter: I) + where + I: IntoIterator, + { + self.as_mut_view().extend(iter) + } +} + +impl<'a, T> Extend<&'a T> for HistoryBufferView where T: 'a + Clone, { @@ -353,20 +688,23 @@ where } } -impl Drop for HistoryBuffer { +impl Drop for HistoryBufferInner { fn drop(&mut self) { - unsafe { - ptr::drop_in_place(ptr::slice_from_raw_parts_mut( - self.data.as_mut_ptr() as *mut T, - self.len(), - )) - } + B::as_mut_hist_view(self).drop_impl(); } } impl Deref for HistoryBuffer { type Target = [T]; + fn deref(&self) -> &[T] { + self.as_view() + } +} + +impl Deref for HistoryBufferView { + type Target = [T]; + fn deref(&self) -> &[T] { self.as_slice() } @@ -379,7 +717,23 @@ impl AsRef<[T]> for HistoryBuffer { } } +impl AsRef<[T]> for HistoryBufferView { + #[inline] + fn as_ref(&self) -> &[T] { + self + } +} + impl fmt::Debug for HistoryBuffer +where + T: fmt::Debug, +{ + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + self.as_view().fmt(f) + } +} + +impl fmt::Debug for HistoryBufferView where T: fmt::Debug, { @@ -395,6 +749,15 @@ impl Default for HistoryBuffer { } impl PartialEq for HistoryBuffer +where + T: PartialEq, +{ + fn eq(&self, other: &Self) -> bool { + self.as_view().eq(other.as_view()) + } +} + +impl PartialEq for HistoryBufferView where T: PartialEq, { @@ -403,6 +766,24 @@ where } } +impl PartialEq> for HistoryBufferView +where + T: PartialEq, +{ + fn eq(&self, other: &HistoryBuffer) -> bool { + self.oldest_ordered().eq(other.as_view().oldest_ordered()) + } +} + +impl PartialEq> for HistoryBuffer +where + T: PartialEq, +{ + fn eq(&self, other: &HistoryBufferView) -> bool { + self.as_view().oldest_ordered().eq(other.oldest_ordered()) + } +} + /// An iterator on the underlying buffer ordered from oldest data to newest #[derive(Clone)] pub struct OldestOrdered<'a, T, const N: usize> { diff --git a/src/lib.rs b/src/lib.rs index b5238c672c..57b3d6bcc5 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -87,7 +87,7 @@ pub use binary_heap::BinaryHeap; pub use deque::Deque; -pub use histbuf::{HistoryBuffer, OldestOrdered}; +pub use histbuf::{HistoryBuffer, HistoryBufferView, OldestOrdered}; pub use indexmap::{ Bucket, Entry, FnvIndexMap, IndexMap, Iter as IndexMapIter, IterMut as IndexMapIterMut, Keys as IndexMapKeys, OccupiedEntry, Pos, VacantEntry, Values as IndexMapValues, From 4a95ffe97fd21abcd189a7635108fa3adb9ef40e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sosth=C3=A8ne=20Gu=C3=A9don?= Date: Thu, 27 Jun 2024 09:52:39 +0200 Subject: [PATCH 2/4] Forward HistoryBuf implementations to HistoryBufView --- src/histbuf.rs | 127 ++++++++++++++++++------------------------------- 1 file changed, 47 insertions(+), 80 deletions(-) diff --git a/src/histbuf.rs b/src/histbuf.rs index e680749195..77c7f110e4 100644 --- a/src/histbuf.rs +++ b/src/histbuf.rs @@ -80,29 +80,29 @@ pub type HistoryBuffer = HistoryBufferInner<[MaybeUninit; /// /// # Examples /// ``` -/// use heapless::HistoryBuffer; +/// use heapless::{HistoryBuffer, HistoryBufferView}; /// /// // Initialize a new buffer with 8 elements. /// let mut buf = HistoryBuffer::<_, 8>::new(); /// let buf_view: &mut HistoryBufferView<_> = &mut buf; /// /// // Starts with no data -/// assert_eq!(buf.recent(), None); +/// assert_eq!(buf_view.recent(), None); /// -/// buf.write(3); -/// buf.write(5); -/// buf.extend(&[4, 4]); +/// buf_view.write(3); +/// buf_view.write(5); +/// buf_view.extend(&[4, 4]); /// /// // The most recent written element is a four. -/// assert_eq!(buf.recent(), Some(&4)); +/// assert_eq!(buf_view.recent(), Some(&4)); /// /// // To access all elements in an unspecified order, use `as_slice()`. -/// for el in buf.as_slice() { +/// for el in buf_view.as_slice() { /// println!("{:?}", el); /// } /// /// // Now we can prepare an average of all values, which comes out to 4. -/// let avg = buf.as_slice().iter().sum::() / buf.len(); +/// let avg = buf_view.as_slice().iter().sum::() / buf_view.len(); /// assert_eq!(avg, 4); /// ``` pub type HistoryBufferView = HistoryBufferInner<[MaybeUninit]>; @@ -299,12 +299,13 @@ impl HistoryBufferView { /// # Examples /// /// ``` - /// use heapless::HistoryBuffer; + /// use heapless::{HistoryBuffer, HistoryBufferView}; /// /// let mut x: HistoryBuffer = HistoryBuffer::new(); - /// x.write(4); - /// x.write(10); - /// assert_eq!(x.recent(), Some(&10)); + /// let mut x_view = &mut x; + /// x_view.write(4); + /// x_view.write(10); + /// assert_eq!(x_view.recent(), Some(&10)); /// ``` pub fn recent(&self) -> Option<&T> { self.recent_index() @@ -316,12 +317,13 @@ impl HistoryBufferView { /// # Examples /// /// ``` - /// use heapless::HistoryBuffer; + /// use heapless::{HistoryBuffer, HistoryBufferView}; /// /// let mut x: HistoryBuffer = HistoryBuffer::new(); - /// x.write(4); - /// x.write(10); - /// assert_eq!(x.recent_index(), Some(1)); + /// let mut x_view = &mut x; + /// x_view.write(4); + /// x_view.write(10); + /// assert_eq!(x_view.recent_index(), Some(1)); /// ``` pub fn recent_index(&self) -> Option { if self.write_at == 0 { @@ -340,12 +342,13 @@ impl HistoryBufferView { /// # Examples /// /// ``` - /// use heapless::HistoryBuffer; + /// use heapless::{HistoryBuffer, HistoryBufferView}; /// /// let mut x: HistoryBuffer = HistoryBuffer::new(); - /// x.write(4); - /// x.write(10); - /// assert_eq!(x.oldest(), Some(&4)); + /// let mut x_view = &mut x; + /// x_view.write(4); + /// x_view.write(10); + /// assert_eq!(x_view.oldest(), Some(&4)); /// ``` pub fn oldest(&self) -> Option<&T> { self.oldest_index() @@ -357,12 +360,13 @@ impl HistoryBufferView { /// # Examples /// /// ``` - /// use heapless::HistoryBuffer; + /// use heapless::{HistoryBuffer, HistoryBufferView}; /// /// let mut x: HistoryBuffer = HistoryBuffer::new(); - /// x.write(4); - /// x.write(10); - /// assert_eq!(x.oldest_index(), Some(0)); + /// let mut x_view = &mut x; + /// x_view.write(4); + /// x_view.write(10); + /// assert_eq!(x_view.oldest_index(), Some(0)); /// ``` pub fn oldest_index(&self) -> Option { if self.filled { @@ -385,12 +389,12 @@ impl HistoryBufferView { /// # Examples /// /// ``` - /// use heapless::HistoryBuffer; - /// + /// use heapless::{HistoryBuffer, HistoryBufferView}; /// let mut buffer: HistoryBuffer = HistoryBuffer::new(); - /// buffer.extend([0, 0, 0]); - /// buffer.extend([1, 2, 3, 4, 5, 6]); - /// assert_eq!(buffer.as_slices(), (&[1, 2, 3][..], &[4, 5, 6][..])); + /// let mut buffer_view: &mut HistoryBufferView = &mut buffer; + /// buffer_view.extend([0, 0, 0]); + /// buffer_view.extend([1, 2, 3, 4, 5, 6]); + /// assert_eq!(buffer_view.as_slices(), (&[1, 2, 3][..], &[4, 5, 6][..])); /// ``` pub fn as_slices(&self) -> (&[T], &[T]) { let buffer = self.as_slice(); @@ -407,12 +411,13 @@ impl HistoryBufferView { /// # Examples /// /// ``` - /// use heapless::HistoryBuffer; + /// use heapless::{HistoryBuffer, HistoryBufferView}; /// /// let mut buffer: HistoryBuffer = HistoryBuffer::new(); - /// buffer.extend([0, 0, 0, 1, 2, 3, 4, 5, 6]); + /// let mut buffer_view: &mut HistoryBufferView = &mut buffer; + /// buffer_view.extend([0, 0, 0, 1, 2, 3, 4, 5, 6]); /// let expected = [1, 2, 3, 4, 5, 6]; - /// for (x, y) in buffer.oldest_ordered().zip(expected.iter()) { + /// for (x, y) in buffer_view.oldest_ordered().zip(expected.iter()) { /// assert_eq!(x, y) /// } /// ``` @@ -426,11 +431,7 @@ impl HistoryBuffer { /// Returns the current fill level of the buffer. #[inline] pub fn len(&self) -> usize { - if self.filled { - N - } else { - self.write_at - } + self.as_view().len() } /// Returns true if the buffer is empty. @@ -445,7 +446,7 @@ impl HistoryBuffer { /// ``` #[inline] pub fn is_empty(&self) -> bool { - self.len() == 0 + self.as_view().is_empty() } /// Returns the capacity of the buffer, which is the length of the @@ -463,17 +464,7 @@ impl HistoryBuffer { /// Writes an element to the buffer, overwriting the oldest value. pub fn write(&mut self, t: T) { - if self.filled { - // Drop the old before we overwrite it. - unsafe { ptr::drop_in_place(self.data[self.write_at].as_mut_ptr()) } - } - self.data[self.write_at] = MaybeUninit::new(t); - - self.write_at += 1; - if self.write_at == self.capacity() { - self.write_at = 0; - self.filled = true; - } + self.as_mut_view().write(t) } /// Clones and writes all elements in a slice to the buffer. @@ -484,9 +475,7 @@ impl HistoryBuffer { where T: Clone, { - for item in other { - self.write(item.clone()); - } + self.as_mut_view().extend_from_slice(other) } /// Returns a reference to the most recently written value. @@ -502,8 +491,7 @@ impl HistoryBuffer { /// assert_eq!(x.recent(), Some(&10)); /// ``` pub fn recent(&self) -> Option<&T> { - self.recent_index() - .map(|i| unsafe { &*self.data[i].as_ptr() }) + self.as_view().recent() } /// Returns index of the most recently written value in the underlying slice. @@ -519,15 +507,7 @@ impl HistoryBuffer { /// assert_eq!(x.recent_index(), Some(1)); /// ``` pub fn recent_index(&self) -> Option { - if self.write_at == 0 { - if self.filled { - Some(self.capacity() - 1) - } else { - None - } - } else { - Some(self.write_at - 1) - } + self.as_view().recent_index() } /// Returns a reference to the oldest value in the buffer. @@ -543,8 +523,7 @@ impl HistoryBuffer { /// assert_eq!(x.oldest(), Some(&4)); /// ``` pub fn oldest(&self) -> Option<&T> { - self.oldest_index() - .map(|i| unsafe { &*self.data[i].as_ptr() }) + self.as_view().oldest() } /// Returns index of the oldest value in the underlying slice. @@ -560,19 +539,13 @@ impl HistoryBuffer { /// assert_eq!(x.oldest_index(), Some(0)); /// ``` pub fn oldest_index(&self) -> Option { - if self.filled { - Some(self.write_at) - } else if self.write_at == 0 { - None - } else { - Some(0) - } + self.as_view().oldest_index() } /// 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] { - unsafe { slice::from_raw_parts(self.data.as_ptr() as *const _, self.len()) } + self.as_view().as_slice() } /// Returns a pair of slices which contain, in order, the contents of the buffer. @@ -588,13 +561,7 @@ impl HistoryBuffer { /// assert_eq!(buffer.as_slices(), (&[1, 2, 3][..], &[4, 5, 6][..])); /// ``` pub fn as_slices(&self) -> (&[T], &[T]) { - let buffer = self.as_slice(); - - if !self.filled { - (buffer, &[]) - } else { - (&buffer[self.write_at..], &buffer[..self.write_at]) - } + self.as_view().as_slices() } /// Returns an iterator for iterating over the buffer from oldest to newest. From 3c17fad6dd824fa9b8cc829bb73f48ebd293c2d9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sosth=C3=A8ne=20Gu=C3=A9don?= Date: Thu, 27 Jun 2024 09:53:11 +0200 Subject: [PATCH 3/4] Update changelog --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0bea10baa6..951a4409c9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -19,6 +19,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/). - Added `VecView`, the `!Sized` version of `Vec`. - Added pool implementations for 64-bit architectures. - Added `IntoIterator` implementation for `LinearMap` +- Added `HistoryBufferView`, the `!Sized` version of `HistoryBuffer`. ### Changed From 010c49847692ad1db62b0f5b18a5dbac6789371e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sosth=C3=A8ne=20Gu=C3=A9don?= Date: Thu, 27 Jun 2024 17:11:44 +0200 Subject: [PATCH 4/4] De-duplicate oldest_ordered implemententation --- src/histbuf.rs | 41 ++++++++++++----------------------------- 1 file changed, 12 insertions(+), 29 deletions(-) diff --git a/src/histbuf.rs b/src/histbuf.rs index 77c7f110e4..c6413a5dc0 100644 --- a/src/histbuf.rs +++ b/src/histbuf.rs @@ -1,4 +1,6 @@ use core::fmt; +use core::iter; +use core::marker::PhantomData; use core::mem::MaybeUninit; use core::ops::Deref; use core::ptr; @@ -422,6 +424,10 @@ impl HistoryBufferView { /// } /// ``` pub fn oldest_ordered(&self) -> impl Iterator { + self.oldest_ordered_inner() + } + + fn oldest_ordered_inner(&self) -> iter::Chain, slice::Iter<'_, T>> { let (old, new) = self.as_slices(); old.iter().chain(new) } @@ -579,19 +585,9 @@ impl HistoryBuffer { /// } /// ``` pub fn oldest_ordered(&self) -> OldestOrdered<'_, T, N> { - if self.filled { - OldestOrdered { - buf: self, - cur: self.write_at, - wrapped: false, - } - } else { - // special case: act like we wrapped already to handle empty buffer. - OldestOrdered { - buf: self, - cur: 0, - wrapped: true, - } + OldestOrdered { + inner: self.as_view().oldest_ordered_inner(), + phantom: PhantomData, } } } @@ -754,28 +750,15 @@ where /// An iterator on the underlying buffer ordered from oldest data to newest #[derive(Clone)] pub struct OldestOrdered<'a, T, const N: usize> { - buf: &'a HistoryBuffer, - cur: usize, - wrapped: bool, + inner: iter::Chain, slice::Iter<'a, T>>, + phantom: PhantomData<[T; N]>, } impl<'a, T, const N: usize> Iterator for OldestOrdered<'a, T, N> { type Item = &'a T; fn next(&mut self) -> Option<&'a T> { - if self.cur == self.buf.len() && self.buf.filled { - // roll-over - self.cur = 0; - self.wrapped = true; - } - - if self.cur == self.buf.write_at && self.wrapped { - return None; - } - - let item = &self.buf[self.cur]; - self.cur += 1; - Some(item) + self.inner.next() } }