@@ -181,6 +181,38 @@ impl<T, const N: usize> HistoryBuffer<T, N> {
181
181
pub fn as_slice ( & self ) -> & [ T ] {
182
182
unsafe { slice:: from_raw_parts ( self . data . as_ptr ( ) as * const _ , self . len ( ) ) }
183
183
}
184
+
185
+ /// Returns an iterator for iterating over the buffer from oldest to newest.
186
+ ///
187
+ /// # Examples
188
+ ///
189
+ /// ```
190
+ /// use heapless::HistoryBuffer;
191
+ ///
192
+ /// let mut buffer: HistoryBuffer<u8, 6> = HistoryBuffer::new();
193
+ /// buffer.extend([0, 0, 0, 1, 2, 3, 4, 5, 6]);
194
+ /// let expected = [1, 2, 3, 4, 5, 6];
195
+ /// for (x, y) in buffer.oldest_ordered().zip(expected.iter()) {
196
+ /// assert_eq!(x, y)
197
+ /// }
198
+ ///
199
+ /// ```
200
+ pub fn oldest_ordered < ' a > ( & ' a self ) -> OldestOrdered < ' a , T , N > {
201
+ if self . filled {
202
+ OldestOrdered {
203
+ buf : self ,
204
+ cur : self . write_at ,
205
+ wrapped : false ,
206
+ }
207
+ } else {
208
+ // special case: act like we wrapped already to handle empty buffer.
209
+ OldestOrdered {
210
+ buf : self ,
211
+ cur : 0 ,
212
+ wrapped : true ,
213
+ }
214
+ }
215
+ }
184
216
}
185
217
186
218
impl < T , const N : usize > Extend < T > for HistoryBuffer < T , N > {
@@ -247,9 +279,38 @@ impl<T, const N: usize> Default for HistoryBuffer<T, N> {
247
279
}
248
280
}
249
281
282
+ /// An iterator on the underlying buffer ordered from oldest data to newest
283
+ #[ derive( Clone ) ]
284
+ pub struct OldestOrdered < ' a , T , const N : usize > {
285
+ buf : & ' a HistoryBuffer < T , N > ,
286
+ cur : usize ,
287
+ wrapped : bool ,
288
+ }
289
+
290
+ impl < ' a , T , const N : usize > Iterator for OldestOrdered < ' a , T , N > {
291
+ type Item = & ' a T ;
292
+
293
+ fn next ( & mut self ) -> Option < & ' a T > {
294
+ if self . cur == self . buf . len ( ) && self . buf . filled {
295
+ // roll-over
296
+ self . cur = 0 ;
297
+ self . wrapped = true ;
298
+ }
299
+
300
+ if self . cur == self . buf . write_at && self . wrapped {
301
+ return None ;
302
+ }
303
+
304
+ let item = & self . buf [ self . cur ] ;
305
+ self . cur += 1 ;
306
+ Some ( item)
307
+ }
308
+ }
309
+
250
310
#[ cfg( test) ]
251
311
mod tests {
252
312
use crate :: HistoryBuffer ;
313
+ use core:: fmt:: Debug ;
253
314
254
315
#[ test]
255
316
fn new ( ) {
@@ -314,4 +375,59 @@ mod tests {
314
375
315
376
assert_eq ! ( x. as_slice( ) , [ 5 , 2 , 3 , 4 ] ) ;
316
377
}
378
+
379
+ #[ test]
380
+ fn ordered ( ) {
381
+ // test on an empty buffer
382
+ let buffer: HistoryBuffer < u8 , 6 > = HistoryBuffer :: new ( ) ;
383
+ let mut iter = buffer. oldest_ordered ( ) ;
384
+ assert_eq ! ( iter. next( ) , None ) ;
385
+ assert_eq ! ( iter. next( ) , None ) ;
386
+
387
+ // test on a un-filled buffer
388
+ let mut buffer: HistoryBuffer < u8 , 6 > = HistoryBuffer :: new ( ) ;
389
+ buffer. extend ( [ 1 , 2 , 3 ] ) ;
390
+ assert_eq ! ( buffer. len( ) , 3 ) ;
391
+ assert_eq_iter ( buffer. oldest_ordered ( ) , & [ 1 , 2 , 3 ] ) ;
392
+
393
+ // test on a filled buffer
394
+ let mut buffer: HistoryBuffer < u8 , 6 > = HistoryBuffer :: new ( ) ;
395
+ buffer. extend ( [ 0 , 0 , 0 , 1 , 2 , 3 , 4 , 5 , 6 ] ) ;
396
+ assert_eq ! ( buffer. len( ) , 6 ) ;
397
+ assert_eq_iter ( buffer. oldest_ordered ( ) , & [ 1 , 2 , 3 , 4 , 5 , 6 ] ) ;
398
+
399
+ // comprehensive test all cases
400
+ for n in 0 ..50 {
401
+ const N : usize = 7 ;
402
+ let mut buffer: HistoryBuffer < u8 , N > = HistoryBuffer :: new ( ) ;
403
+ buffer. extend ( 0 ..n) ;
404
+ assert_eq_iter (
405
+ buffer. oldest_ordered ( ) . copied ( ) ,
406
+ n. saturating_sub ( N as u8 ) ..n,
407
+ ) ;
408
+ }
409
+ }
410
+
411
+ /// Compares two iterators item by item, making sure they stop at the same time.
412
+ fn assert_eq_iter < I : Eq + Debug > (
413
+ a : impl IntoIterator < Item = I > ,
414
+ b : impl IntoIterator < Item = I > ,
415
+ ) {
416
+ let mut a = a. into_iter ( ) ;
417
+ let mut b = b. into_iter ( ) ;
418
+
419
+ let mut i = 0 ;
420
+ loop {
421
+ let a_item = a. next ( ) ;
422
+ let b_item = b. next ( ) ;
423
+
424
+ assert_eq ! ( a_item, b_item, "{}" , i) ;
425
+
426
+ i += 1 ;
427
+
428
+ if b_item. is_none ( ) {
429
+ break ;
430
+ }
431
+ }
432
+ }
317
433
}
0 commit comments