1+ //! A "history buffer", similar to a write-only ring buffer of fixed length.
2+ //!
3+ //! This buffer keeps a fixed number of elements. On write, the oldest element
4+ //! is overwritten. Thus, the buffer is useful to keep a history of values with
5+ //! some desired depth, and for example calculate a rolling average.
6+ //!
7+ //! # Examples
8+ //! ```
9+ //! use heapless::HistoryBuffer;
10+ //!
11+ //! // Initialize a new buffer with 8 elements.
12+ //! let mut buf = HistoryBuffer::<_, 8>::new();
13+ //!
14+ //! // Starts with no data
15+ //! assert_eq!(buf.recent(), None);
16+ //!
17+ //! buf.write(3);
18+ //! buf.write(5);
19+ //! buf.extend(&[4, 4]);
20+ //!
21+ //! // The most recent written element is a four.
22+ //! assert_eq!(buf.recent(), Some(&4));
23+ //!
24+ //! // To access all elements in an unspecified order, use `as_slice()`.
25+ //! for el in buf.as_slice() {
26+ //! println!("{:?}", el);
27+ //! }
28+ //!
29+ //! // Now we can prepare an average of all values, which comes out to 4.
30+ //! let avg = buf.as_slice().iter().sum::<usize>() / buf.len();
31+ //! assert_eq!(avg, 4);
32+ //! ```
33+
34+ use core:: borrow:: Borrow ;
35+ use core:: borrow:: BorrowMut ;
136use core:: fmt;
37+ use core:: marker:: PhantomData ;
238use core:: mem:: MaybeUninit ;
339use core:: ops:: Deref ;
440use core:: ptr;
541use core:: slice;
642
43+ use crate :: storage:: OwnedStorage ;
44+ use crate :: storage:: Storage ;
45+ use crate :: storage:: ViewStorage ;
46+
47+ /// Base struct for [`HistoryBuffer`] and [`HistoryBufferView`], generic over the [`Storage`].
48+ ///
49+ /// In most cases you should use [`HistoryBuffer`] or [`HistoryBufferView`] directly. Only use this
50+ /// struct if you want to write code that's generic over both.
51+ pub struct HistoryBufferInner < T , S : Storage > {
52+ write_at : usize ,
53+ filled : bool ,
54+ data : S :: Buffer < MaybeUninit < T > > ,
55+ }
56+
757/// A "history buffer", similar to a write-only ring buffer of fixed length.
858///
959/// This buffer keeps a fixed number of elements. On write, the oldest element
@@ -36,11 +86,40 @@ use core::slice;
3686/// let avg = buf.as_slice().iter().sum::<usize>() / buf.len();
3787/// assert_eq!(avg, 4);
3888/// ```
39- pub struct HistoryBuffer < T , const N : usize > {
40- data : [ MaybeUninit < T > ; N ] ,
41- write_at : usize ,
42- filled : bool ,
43- }
89+ pub type HistoryBuffer < T , const N : usize > = HistoryBufferInner < T , OwnedStorage < N > > ;
90+
91+ /// A "view" into a [`HistoryBuffer`]
92+ ///
93+ /// Unlike [`HistoryBuffer`], it doesn't have the `const N: usize` in its type signature.
94+ ///
95+ /// # Examples
96+ /// ```
97+ /// use heapless::HistoryBuffer;
98+ ///
99+ /// // Initialize a new buffer with 8 elements.
100+ /// let mut owned_buf = HistoryBuffer::<_, 8>::new();
101+ /// let buf: &mut HistoryBufferView<_> = &mut owned_buf;
102+ ///
103+ /// // Starts with no data
104+ /// assert_eq!(buf.recent(), None);
105+ ///
106+ /// buf.write(3);
107+ /// buf.write(5);
108+ /// buf.extend(&[4, 4]);
109+ ///
110+ /// // The most recent written element is a four.
111+ /// assert_eq!(buf.recent(), Some(&4));
112+ ///
113+ /// // To access all elements in an unspecified order, use `as_slice()`.
114+ /// for el in buf.as_slice() {
115+ /// println!("{:?}", el);
116+ /// }
117+ ///
118+ /// // Now we can prepare an average of all values, which comes out to 4.
119+ /// let avg = buf.as_slice().iter().sum::<usize>() / buf.len();
120+ /// assert_eq!(avg, 4);
121+ /// ```
122+ pub type HistoryBufferView < T > = HistoryBufferInner < T , ViewStorage > ;
44123
45124impl < T , const N : usize > HistoryBuffer < T , N > {
46125 const INIT : MaybeUninit < T > = MaybeUninit :: uninit ( ) ;
@@ -69,12 +148,6 @@ impl<T, const N: usize> HistoryBuffer<T, N> {
69148 filled : false ,
70149 }
71150 }
72-
73- /// Clears the buffer, replacing every element with the default value of
74- /// type `T`.
75- pub fn clear ( & mut self ) {
76- * self = Self :: new ( ) ;
77- }
78151}
79152
80153impl < T , const N : usize > HistoryBuffer < T , N >
@@ -101,19 +174,46 @@ where
101174 filled : true ,
102175 }
103176 }
104-
177+ }
178+ impl < T : Copy , S : Storage > HistoryBufferInner < T , S > {
105179 /// Clears the buffer, replacing every element with the given value.
106180 pub fn clear_with ( & mut self , t : T ) {
107- * self = Self :: new_with ( t) ;
181+ // SAFETY: we reset the values just after
182+ unsafe { self . drop_contents ( ) } ;
183+ self . write_at = 0 ;
184+ self . filled = true ;
185+
186+ for d in self . data . borrow_mut ( ) {
187+ * d = MaybeUninit :: new ( t) ;
188+ }
108189 }
109190}
110191
111- impl < T , const N : usize > HistoryBuffer < T , N > {
192+ impl < T , S : Storage > HistoryBufferInner < T , S > {
193+ /// Clears the buffer
194+ pub fn clear ( & mut self ) {
195+ // SAFETY: we reset the values just after
196+ unsafe { self . drop_contents ( ) } ;
197+ self . write_at = 0 ;
198+ self . filled = false ;
199+ }
200+ }
201+
202+ impl < T , S : Storage > HistoryBufferInner < T , S > {
203+ unsafe fn drop_contents ( & mut self ) {
204+ unsafe {
205+ ptr:: drop_in_place ( ptr:: slice_from_raw_parts_mut (
206+ self . data . borrow_mut ( ) . as_mut_ptr ( ) as * mut T ,
207+ self . len ( ) ,
208+ ) )
209+ }
210+ }
211+
112212 /// Returns the current fill level of the buffer.
113213 #[ inline]
114214 pub fn len ( & self ) -> usize {
115215 if self . filled {
116- N
216+ self . capacity ( )
117217 } else {
118218 self . write_at
119219 }
@@ -138,7 +238,7 @@ impl<T, const N: usize> HistoryBuffer<T, N> {
138238 /// underlying backing array.
139239 #[ inline]
140240 pub fn capacity ( & self ) -> usize {
141- N
241+ self . data . borrow ( ) . len ( )
142242 }
143243
144244 /// Returns whether the buffer is full
@@ -151,9 +251,9 @@ impl<T, const N: usize> HistoryBuffer<T, N> {
151251 pub fn write ( & mut self , t : T ) {
152252 if self . filled {
153253 // Drop the old before we overwrite it.
154- unsafe { ptr:: drop_in_place ( self . data [ self . write_at ] . as_mut_ptr ( ) ) }
254+ unsafe { ptr:: drop_in_place ( self . data . borrow_mut ( ) [ self . write_at ] . as_mut_ptr ( ) ) }
155255 }
156- self . data [ self . write_at ] = MaybeUninit :: new ( t) ;
256+ self . data . borrow_mut ( ) [ self . write_at ] = MaybeUninit :: new ( t) ;
157257
158258 self . write_at += 1 ;
159259 if self . write_at == self . capacity ( ) {
@@ -189,7 +289,7 @@ impl<T, const N: usize> HistoryBuffer<T, N> {
189289 /// ```
190290 pub fn recent ( & self ) -> Option < & T > {
191291 self . recent_index ( )
192- . map ( |i| unsafe { & * self . data [ i] . as_ptr ( ) } )
292+ . map ( |i| unsafe { & * self . data . borrow ( ) [ i] . as_ptr ( ) } )
193293 }
194294
195295 /// Returns index of the most recently written value in the underlying slice.
@@ -230,7 +330,7 @@ impl<T, const N: usize> HistoryBuffer<T, N> {
230330 /// ```
231331 pub fn oldest ( & self ) -> Option < & T > {
232332 self . oldest_index ( )
233- . map ( |i| unsafe { & * self . data [ i] . as_ptr ( ) } )
333+ . map ( |i| unsafe { & * self . data . borrow ( ) [ i] . as_ptr ( ) } )
234334 }
235335
236336 /// Returns index of the oldest value in the underlying slice.
@@ -258,7 +358,7 @@ impl<T, const N: usize> HistoryBuffer<T, N> {
258358 /// Returns the array slice backing the buffer, without keeping track
259359 /// of the write position. Therefore, the element order is unspecified.
260360 pub fn as_slice ( & self ) -> & [ T ] {
261- unsafe { slice:: from_raw_parts ( self . data . as_ptr ( ) as * const _ , self . len ( ) ) }
361+ unsafe { slice:: from_raw_parts ( self . data . borrow ( ) . as_ptr ( ) as * const _ , self . len ( ) ) }
262362 }
263363
264364 /// Returns a pair of slices which contain, in order, the contents of the buffer.
@@ -298,20 +398,11 @@ impl<T, const N: usize> HistoryBuffer<T, N> {
298398 /// assert_eq!(x, y)
299399 /// }
300400 /// ```
301- pub fn oldest_ordered ( & self ) -> OldestOrdered < ' _ , T , N > {
302- match ( self . oldest_index ( ) , self . recent_index ( ) ) {
303- ( Some ( oldest_index) , Some ( recent_index) ) => OldestOrdered {
304- buf : self ,
305- next : oldest_index,
306- back : recent_index,
307- done : false ,
308- } ,
309- _ => OldestOrdered {
310- buf : self ,
311- next : 0 ,
312- back : 0 ,
313- done : true ,
314- } ,
401+ pub fn oldest_ordered ( & self ) -> OldestOrderedInner < ' _ , T , S > {
402+ let ( old, new) = self . as_slices ( ) ;
403+ OldestOrderedInner {
404+ phantom : PhantomData ,
405+ inner : old. iter ( ) . chain ( new) ,
315406 }
316407 }
317408}
@@ -354,14 +445,9 @@ where
354445 }
355446}
356447
357- impl < T , const N : usize > Drop for HistoryBuffer < T , N > {
448+ impl < T , S : Storage > Drop for HistoryBufferInner < T , S > {
358449 fn drop ( & mut self ) {
359- unsafe {
360- ptr:: drop_in_place ( ptr:: slice_from_raw_parts_mut (
361- self . data . as_mut_ptr ( ) as * mut T ,
362- self . len ( ) ,
363- ) )
364- }
450+ unsafe { self . drop_contents ( ) }
365451 }
366452}
367453
@@ -404,51 +490,74 @@ where
404490 }
405491}
406492
493+ /// Base struct for [`OldestOrdered`] and [`OldestOrderedView`], generic over the [`Storage`].
494+ ///
495+ /// In most cases you should use [`OldestOrdered`] or [`OldestOrderedView`] directly. Only use this
496+ /// struct if you want to write code that's generic over both.
497+ pub struct OldestOrderedInner < ' a , T , S : Storage > {
498+ phantom : PhantomData < S > ,
499+ inner : core:: iter:: Chain < core:: slice:: Iter < ' a , T > , core:: slice:: Iter < ' a , T > > ,
500+ }
501+
407502/// Double ended iterator on the underlying buffer ordered from the oldest data
408503/// to the newest
409- #[ derive( Clone ) ]
410- pub struct OldestOrdered < ' a , T , const N : usize > {
411- buf : & ' a HistoryBuffer < T , N > ,
412- next : usize ,
413- back : usize ,
414- done : bool ,
415- }
504+ /// This type exists for backwards compatibility. It is always better to convert it to an [`OldestOrderedView`] with [`into_view`](OldestOrdered::into_view)
505+ pub type OldestOrdered < ' a , T , const N : usize > = OldestOrderedInner < ' a , T , OwnedStorage < N > > ;
416506
417- impl < ' a , T , const N : usize > Iterator for OldestOrdered < ' a , T , N > {
418- type Item = & ' a T ;
507+ /// Double ended iterator on the underlying buffer ordered from the oldest data
508+ /// to the newest
509+ pub type OldestOrderedView < ' a , T > = OldestOrderedInner < ' a , T , ViewStorage > ;
419510
420- fn next ( & mut self ) -> Option < & ' a T > {
421- if self . done {
422- return None ;
511+ impl < ' a , T , const N : usize > OldestOrdered < ' a , T , N > {
512+ /// Remove the `N` const-generic parameter from the iterator
513+ ///
514+ /// For the opposite operation, see [`into_legacy_iter`](OldestOrderedView::into_legacy_iter)
515+ pub fn into_view ( self ) -> OldestOrderedView < ' a , T > {
516+ OldestOrderedView {
517+ phantom : PhantomData ,
518+ inner : self . inner ,
423519 }
520+ }
521+ }
424522
425- if self . next == self . back {
426- self . done = true ;
523+ impl < ' a , T > OldestOrderedView < ' a , T > {
524+ /// Add back the `N` const-generic parameter to use it with APIs expecting the legacy type
525+ ///
526+ /// You probably do not need this
527+ ///
528+ /// For the opposite operation, see [`into_view`](OldestOrdered::into_view)
529+ pub fn into_legacy_iter < const N : usize > ( self ) -> OldestOrdered < ' a , T , N > {
530+ OldestOrdered {
531+ phantom : PhantomData ,
532+ inner : self . inner ,
427533 }
428-
429- let item = & self . buf [ self . next ] ;
430-
431- self . next = if self . next == N - 1 { 0 } else { self . next + 1 } ;
432-
433- Some ( item)
434534 }
435535}
436536
437- impl < ' a , T , const N : usize > DoubleEndedIterator for OldestOrdered < ' a , T , N > {
438- fn next_back ( & mut self ) -> Option < Self :: Item > {
439- if self . done {
440- return None ;
537+ impl < ' a , T , S : Storage > Clone for OldestOrderedInner < ' a , T , S > {
538+ fn clone ( & self ) -> Self {
539+ Self {
540+ phantom : PhantomData ,
541+ inner : self . inner . clone ( ) ,
441542 }
543+ }
544+ }
442545
443- if self . next == self . back {
444- self . done = true ;
445- }
546+ impl < ' a , T , S : Storage > Iterator for OldestOrderedInner < ' a , T , S > {
547+ type Item = & ' a T ;
446548
447- let item = & self . buf [ self . back ] ;
549+ fn next ( & mut self ) -> Option < & ' a T > {
550+ self . inner . next ( )
551+ }
448552
449- self . back = if self . back == 0 { N - 1 } else { self . back - 1 } ;
553+ fn size_hint ( & self ) -> ( usize , Option < usize > ) {
554+ self . inner . size_hint ( )
555+ }
556+ }
450557
451- Some ( item)
558+ impl < ' a , T , const N : usize > DoubleEndedIterator for OldestOrdered < ' a , T , N > {
559+ fn next_back ( & mut self ) -> Option < Self :: Item > {
560+ self . inner . next_back ( )
452561 }
453562}
454563
0 commit comments