@@ -160,6 +160,15 @@ pub mod experimental {
160
160
self . chunks . iter_chunks_from ( position)
161
161
}
162
162
163
+ /// Iterate over the chunks, starting from `position`, backward — i.e.
164
+ /// to the latest chunk.
165
+ pub fn iter_chunks_backward_from < ' a > (
166
+ & ' a self ,
167
+ position : ChunkPosition ,
168
+ ) -> Result < LinkedChunkIterBackward < ' a , Event , CHUNK_CAPACITY > , LinkedChunkError > {
169
+ self . chunks . iter_chunks_backward_from ( position)
170
+ }
171
+
163
172
/// Iterate over the events.
164
173
///
165
174
/// The most recent event comes first.
@@ -174,6 +183,15 @@ pub mod experimental {
174
183
) -> Result < impl Iterator < Item = ( ItemPosition , & ' a Event ) > , LinkedChunkError > {
175
184
self . chunks . iter_items_from ( position)
176
185
}
186
+
187
+ /// Iterate over the events, starting from `position`, backward — i.e.
188
+ /// to the latest event.
189
+ pub fn iter_events_backward_from < ' a > (
190
+ & ' a self ,
191
+ position : ItemPosition ,
192
+ ) -> Result < impl Iterator < Item = ( ItemPosition , & ' a Event ) > , LinkedChunkError > {
193
+ self . chunks . iter_items_backward_from ( position)
194
+ }
177
195
}
178
196
179
197
#[ derive( Debug ) ]
@@ -298,6 +316,10 @@ pub mod experimental {
298
316
Ok ( ( ) )
299
317
}
300
318
319
+ /// Insert a gap at a specified position in the [`LinkedChunk`].
320
+ ///
321
+ /// Because the `position` can be invalid, this method returns a
322
+ /// `Result`.
301
323
fn insert_gap_at ( & mut self , position : ItemPosition ) -> Result < ( ) , LinkedChunkError > {
302
324
let chunk_index = position. chunk_index ( ) ;
303
325
let item_index = position. item_index ( ) ;
@@ -414,14 +436,31 @@ pub mod experimental {
414
436
) )
415
437
}
416
438
439
+ /// Iterate over the chunks, starting from `position`, backward.
440
+ ///
441
+ /// It iterates from the chunk at `position` to the last chunk.
442
+ fn iter_chunks_backward_from < ' a > (
443
+ & ' a self ,
444
+ position : ChunkPosition ,
445
+ ) -> Result < LinkedChunkIterBackward < ' a , T , C > , LinkedChunkError > {
446
+ Ok ( LinkedChunkIterBackward :: new (
447
+ self . nth_chunk ( position)
448
+ . ok_or ( LinkedChunkError :: InvalidChunkIndex { index : position } ) ?,
449
+ position,
450
+ ) )
451
+ }
452
+
417
453
/// Iterate over the items.
418
454
///
419
- /// It iterates from the last the first item.
455
+ /// It iterates from the last to the first item.
420
456
fn iter_items < ' a > ( & ' a self ) -> impl Iterator < Item = ( ItemPosition , & ' a T ) > {
421
457
self . iter_items_from ( ItemPosition ( 0 , 0 ) )
422
458
. expect ( "`iter_items_from` cannot fail because at least one empty chunk must exist" )
423
459
}
424
460
461
+ /// Iterate over the items, starting from `position`.
462
+ ///
463
+ /// It iterates from the item at `position` to the first item.
425
464
fn iter_items_from < ' a > (
426
465
& ' a self ,
427
466
position : ItemPosition ,
@@ -439,6 +478,26 @@ pub mod experimental {
439
478
. flatten ( )
440
479
. skip ( position. item_index ( ) ) )
441
480
}
481
+
482
+ /// Iterate over the items, stargin from `position`, backward.
483
+ ///
484
+ /// It iterates from the item at `position` to the last item.
485
+ fn iter_items_backward_from < ' a > (
486
+ & ' a self ,
487
+ position : ItemPosition ,
488
+ ) -> Result < impl Iterator < Item = ( ItemPosition , & ' a T ) > , LinkedChunkError > {
489
+ Ok ( self
490
+ . iter_chunks_backward_from ( position. chunk_index ( ) ) ?
491
+ . filter_map ( |( chunk_index, chunk) | match & chunk. content {
492
+ ChunkContent :: Gap => None ,
493
+ ChunkContent :: Items ( items) => {
494
+ Some ( items. iter ( ) . rev ( ) . enumerate ( ) . rev ( ) . map ( move |( item_index, item) | {
495
+ ( ItemPosition ( chunk_index, item_index) , item)
496
+ } ) )
497
+ }
498
+ } )
499
+ . flatten ( ) )
500
+ }
442
501
}
443
502
444
503
/// The position of a chunk in a [`LinkedChunk`].
@@ -465,7 +524,8 @@ pub mod experimental {
465
524
}
466
525
}
467
526
468
- /// An iterator over a [`LinkedChunk`].
527
+ /// An iterator over a [`LinkedChunk`] that traverses the chunk in forward
528
+ /// direction (i.e. it call `previous` on each chunk to make progress).
469
529
pub struct LinkedChunkIter < ' a , T , const CHUNK_CAPACITY : usize > {
470
530
chunk : Option < & ' a Chunk < T , CHUNK_CAPACITY > > ,
471
531
position : ChunkPosition ,
@@ -495,6 +555,37 @@ pub mod experimental {
495
555
}
496
556
}
497
557
558
+ /// An iterator over a [`LinkedChunk`] that traverses the chunk in backward
559
+ /// direction (i.e. it call `next` on each chunk to make progress).
560
+ pub struct LinkedChunkIterBackward < ' a , T , const CHUNK_CAPACITY : usize > {
561
+ chunk : Option < & ' a Chunk < T , CHUNK_CAPACITY > > ,
562
+ position : ChunkPosition ,
563
+ }
564
+
565
+ impl < ' a , T , const C : usize > LinkedChunkIterBackward < ' a , T , C > {
566
+ /// Create a new [`LinkedChunkIter`] from a particular [`Chunk`].
567
+ fn new ( from_chunk : & ' a Chunk < T , C > , position : ChunkPosition ) -> Self {
568
+ Self { chunk : Some ( from_chunk) , position }
569
+ }
570
+ }
571
+
572
+ impl < ' a , T , const C : usize > Iterator for LinkedChunkIterBackward < ' a , T , C > {
573
+ type Item = ( ChunkPosition , & ' a Chunk < T , C > ) ;
574
+
575
+ fn next ( & mut self ) -> Option < Self :: Item > {
576
+ let Some ( chunk) = self . chunk else {
577
+ return None ;
578
+ } ;
579
+
580
+ let position = self . position ;
581
+
582
+ self . chunk = chunk. next ( ) ;
583
+ self . position = self . position . saturating_sub ( 1 ) ;
584
+
585
+ Some ( ( position, chunk) )
586
+ }
587
+ }
588
+
498
589
/// This enum represents the content of a [`Chunk`].
499
590
#[ derive( Debug ) ]
500
591
pub enum ChunkContent < T > {
@@ -886,6 +977,7 @@ pub mod experimental {
886
977
}
887
978
) ;
888
979
assert_matches ! ( iterator. next( ) , Some ( ( 2 , Chunk { content: ChunkContent :: Gap , .. } ) ) ) ;
980
+ // ^ it increases!
889
981
assert_matches ! (
890
982
iterator. next( ) ,
891
983
Some ( ( 3 , Chunk { content: ChunkContent :: Items ( items) , .. } ) ) => {
@@ -897,6 +989,36 @@ pub mod experimental {
897
989
Ok ( ( ) )
898
990
}
899
991
992
+ #[ test]
993
+ fn test_iter_chunks_backward_from ( ) -> Result < ( ) , LinkedChunkError > {
994
+ let mut events = Events :: < char , 2 > :: new ( ) ;
995
+ events. push_events ( [ 'a' , 'b' ] ) ;
996
+ events. push_gap ( ) ;
997
+ events. push_events ( [ 'c' , 'd' , 'e' ] ) ;
998
+
999
+ let mut iterator = events. iter_chunks_backward_from (
1000
+ events. event_position ( |event| * event == 'c' ) . unwrap ( ) . chunk_index ( ) ,
1001
+ ) ?;
1002
+
1003
+ assert_matches ! (
1004
+ iterator. next( ) ,
1005
+ Some ( ( 1 , Chunk { content: ChunkContent :: Items ( items) , .. } ) ) => {
1006
+ // ^ it does not start at 0!
1007
+ assert_eq!( items, & [ 'c' , 'd' ] ) ;
1008
+ }
1009
+ ) ;
1010
+ assert_matches ! (
1011
+ iterator. next( ) ,
1012
+ Some ( ( 0 , Chunk { content: ChunkContent :: Items ( items) , .. } ) ) => {
1013
+ // ^ it decreases!
1014
+ assert_eq!( items, & [ 'e' ] ) ;
1015
+ }
1016
+ ) ;
1017
+ assert_matches ! ( iterator. next( ) , None ) ;
1018
+
1019
+ Ok ( ( ) )
1020
+ }
1021
+
900
1022
#[ test]
901
1023
fn test_iter_items ( ) {
902
1024
let mut events = Events :: < char , 2 > :: new ( ) ;
@@ -932,6 +1054,24 @@ pub mod experimental {
932
1054
Ok ( ( ) )
933
1055
}
934
1056
1057
+ #[ test]
1058
+ fn test_iter_items_backward_from ( ) -> Result < ( ) , LinkedChunkError > {
1059
+ let mut events = Events :: < char , 2 > :: new ( ) ;
1060
+ events. push_events ( [ 'a' , 'b' ] ) ;
1061
+ events. push_gap ( ) ;
1062
+ events. push_events ( [ 'c' , 'd' , 'e' ] ) ;
1063
+
1064
+ let mut iterator = events
1065
+ . iter_events_backward_from ( events. event_position ( |event| * event == 'c' ) . unwrap ( ) ) ?;
1066
+
1067
+ assert_matches ! ( iterator. next( ) , Some ( ( ItemPosition ( 1 , 1 ) , 'c' ) ) ) ;
1068
+ assert_matches ! ( iterator. next( ) , Some ( ( ItemPosition ( 1 , 0 ) , 'd' ) ) ) ;
1069
+ assert_matches ! ( iterator. next( ) , Some ( ( ItemPosition ( 0 , 0 ) , 'e' ) ) ) ;
1070
+ assert_matches ! ( iterator. next( ) , None ) ;
1071
+
1072
+ Ok ( ( ) )
1073
+ }
1074
+
935
1075
#[ test]
936
1076
fn test_insert_items_at ( ) -> Result < ( ) , LinkedChunkError > {
937
1077
let mut events = Events :: < char , 3 > :: new ( ) ;
0 commit comments