@@ -124,6 +124,7 @@ pub mod experimental {
124
124
self . chunks . insert_items_at ( events. into_iter ( ) , position)
125
125
}
126
126
127
+ /// Insert a gap at a specified position.
127
128
pub fn insert_gap_at ( & mut self , position : ItemPosition ) -> Result < ( ) , LinkedChunkError > {
128
129
self . chunks . insert_gap_at ( position)
129
130
}
@@ -151,6 +152,14 @@ pub mod experimental {
151
152
self . chunks . iter_chunks ( )
152
153
}
153
154
155
+ /// Iterate over the chunks, starting from `position`.
156
+ pub fn iter_chunks_from < ' a > (
157
+ & ' a self ,
158
+ position : ChunkPosition ,
159
+ ) -> Result < LinkedChunkIter < ' a , Event , CHUNK_CAPACITY > , LinkedChunkError > {
160
+ self . chunks . iter_chunks_from ( position)
161
+ }
162
+
154
163
/// Iterate over the events.
155
164
///
156
165
/// The most recent event comes first.
@@ -332,9 +341,19 @@ pub mod experimental {
332
341
Ok ( ( ) )
333
342
}
334
343
344
+ /// Get the nth chunk as a reference, if it exists.
345
+ fn nth_chunk < ' a > ( & ' a self , nth : ChunkPosition ) -> Option < & ' a Chunk < T , C > > {
346
+ let mut chunk =
347
+ self . last . or ( Some ( self . first ) ) . as_ref ( ) . map ( |chunk| unsafe { chunk. as_ref ( ) } ) ;
348
+
349
+ for _ in 0 ..nth {
350
+ chunk = chunk?. previous ( ) ;
351
+ }
352
+
353
+ chunk
354
+ }
355
+
335
356
/// Get the nth chunk as a mutable reference, if it exists.
336
- ///
337
- /// 0 represents the last chunk.
338
357
fn nth_chunk_mut < ' a > ( & ' a mut self , nth : ChunkPosition ) -> Option < & ' a mut Chunk < T , C > > {
339
358
let mut chunk =
340
359
self . last . or ( Some ( self . first ) ) . as_mut ( ) . map ( |chunk| unsafe { chunk. as_mut ( ) } ) ;
@@ -368,7 +387,22 @@ pub mod experimental {
368
387
///
369
388
/// It iterates from the last to the first chunk.
370
389
fn iter_chunks < ' a > ( & ' a self ) -> LinkedChunkIter < ' a , T , C > {
371
- LinkedChunkIter :: new ( unsafe { self . last . unwrap_or ( self . first ) . as_ref ( ) } )
390
+ self . iter_chunks_from ( 0 )
391
+ . expect ( "`iter_chunks_from` cannot fail because at least one chunk must exist" )
392
+ }
393
+
394
+ /// Iterate over the chunks, starting from `position`.
395
+ ///
396
+ /// It iterates from the chunk at `position` to the first chunk.
397
+ fn iter_chunks_from < ' a > (
398
+ & ' a self ,
399
+ position : ChunkPosition ,
400
+ ) -> Result < LinkedChunkIter < ' a , T , C > , LinkedChunkError > {
401
+ Ok ( LinkedChunkIter :: new (
402
+ self . nth_chunk ( position)
403
+ . ok_or ( LinkedChunkError :: InvalidChunkIndex { index : position } ) ?,
404
+ position,
405
+ ) )
372
406
}
373
407
374
408
/// Iterate over the items.
@@ -389,9 +423,14 @@ pub mod experimental {
389
423
}
390
424
391
425
/// The position of a chunk in a [`LinkedChunk`].
426
+ ///
427
+ /// 0 represents the latest chunk.
392
428
type ChunkPosition = usize ;
393
429
394
430
/// The position of an item in a [`LinkedChunk`].
431
+ ///
432
+ /// It's a pair of a chunk position and an item index. `(…, 0)` represents
433
+ /// the last item in the chunk.
395
434
#[ derive( Debug , PartialEq ) ]
396
435
pub struct ItemPosition ( ChunkPosition , usize ) ;
397
436
@@ -410,13 +449,13 @@ pub mod experimental {
410
449
/// An iterator over a [`LinkedChunk`].
411
450
pub struct LinkedChunkIter < ' a , T , const CHUNK_CAPACITY : usize > {
412
451
chunk : Option < & ' a Chunk < T , CHUNK_CAPACITY > > ,
413
- position : usize ,
452
+ position : ChunkPosition ,
414
453
}
415
454
416
455
impl < ' a , T , const C : usize > LinkedChunkIter < ' a , T , C > {
417
456
/// Create a new [`LinkedChunkIter`] from a particular [`Chunk`].
418
- fn new ( from_chunk : & ' a Chunk < T , C > ) -> Self {
419
- Self { chunk : Some ( from_chunk) , position : 0 }
457
+ fn new ( from_chunk : & ' a Chunk < T , C > , position : ChunkPosition ) -> Self {
458
+ Self { chunk : Some ( from_chunk) , position }
420
459
}
421
460
}
422
461
@@ -439,7 +478,7 @@ pub mod experimental {
439
478
440
479
/// This enum represents the content of a [`Chunk`].
441
480
#[ derive( Debug ) ]
442
- enum ChunkContent < T > {
481
+ pub enum ChunkContent < T > {
443
482
/// The chunk represents a gap in the linked chunk, i.e. a hole. It
444
483
/// means that some items are missing in this location.
445
484
Gap ,
@@ -672,7 +711,7 @@ pub mod experimental {
672
711
mod tests {
673
712
use assert_matches:: assert_matches;
674
713
675
- use super :: { Events , ItemPosition , LinkedChunkError } ;
714
+ use super :: { Chunk , ChunkContent , Events , ItemPosition , LinkedChunkError } ;
676
715
677
716
macro_rules! assert_events_eq {
678
717
( @_ [ $iterator: ident, $chunk_index: ident, $event_index: ident ] { [ -] $( $rest: tt ) * } { $( $accumulator: tt ) * } ) => {
@@ -778,6 +817,67 @@ pub mod experimental {
778
817
assert_eq ! ( events. event_position( |event| * event == 'e' ) , Some ( ItemPosition ( 3 , 1 ) ) ) ;
779
818
}
780
819
820
+ #[ test]
821
+ fn test_iter_chunks ( ) {
822
+ let mut events = Events :: < char , 2 > :: new ( ) ;
823
+ events. push_events ( [ 'a' , 'b' ] ) ;
824
+ events. push_gap ( ) ;
825
+ events. push_events ( [ 'c' , 'd' , 'e' ] ) ;
826
+
827
+ let mut iterator = events. iter_chunks ( ) ;
828
+
829
+ assert_matches ! (
830
+ iterator. next( ) ,
831
+ Some ( ( 0 , Chunk { content: ChunkContent :: Items ( items) , .. } ) ) => {
832
+ assert_eq!( items, & [ 'e' ] ) ;
833
+ }
834
+ ) ;
835
+ assert_matches ! (
836
+ iterator. next( ) ,
837
+ Some ( ( 1 , Chunk { content: ChunkContent :: Items ( items) , .. } ) ) => {
838
+ assert_eq!( items, & [ 'c' , 'd' ] ) ;
839
+ }
840
+ ) ;
841
+ assert_matches ! ( iterator. next( ) , Some ( ( 2 , Chunk { content: ChunkContent :: Gap , .. } ) ) ) ;
842
+ assert_matches ! (
843
+ iterator. next( ) ,
844
+ Some ( ( 3 , Chunk { content: ChunkContent :: Items ( items) , .. } ) ) => {
845
+ assert_eq!( items, & [ 'a' , 'b' ] ) ;
846
+ }
847
+ ) ;
848
+ assert_matches ! ( iterator. next( ) , None ) ;
849
+ }
850
+
851
+ #[ test]
852
+ fn test_iter_chunks_from ( ) -> Result < ( ) , LinkedChunkError > {
853
+ let mut events = Events :: < char , 2 > :: new ( ) ;
854
+ events. push_events ( [ 'a' , 'b' ] ) ;
855
+ events. push_gap ( ) ;
856
+ events. push_events ( [ 'c' , 'd' , 'e' ] ) ;
857
+
858
+ let mut iterator = events. iter_chunks_from (
859
+ events. event_position ( |event| * event == 'c' ) . unwrap ( ) . chunk_index ( ) ,
860
+ ) ?;
861
+
862
+ assert_matches ! (
863
+ iterator. next( ) ,
864
+ Some ( ( 1 , Chunk { content: ChunkContent :: Items ( items) , .. } ) ) => {
865
+ // ^ it does not start at 0!
866
+ assert_eq!( items, & [ 'c' , 'd' ] ) ;
867
+ }
868
+ ) ;
869
+ assert_matches ! ( iterator. next( ) , Some ( ( 2 , Chunk { content: ChunkContent :: Gap , .. } ) ) ) ;
870
+ assert_matches ! (
871
+ iterator. next( ) ,
872
+ Some ( ( 3 , Chunk { content: ChunkContent :: Items ( items) , .. } ) ) => {
873
+ assert_eq!( items, & [ 'a' , 'b' ] ) ;
874
+ }
875
+ ) ;
876
+ assert_matches ! ( iterator. next( ) , None ) ;
877
+
878
+ Ok ( ( ) )
879
+ }
880
+
781
881
#[ test]
782
882
fn test_insert_items_at ( ) -> Result < ( ) , LinkedChunkError > {
783
883
let mut events = Events :: < char , 3 > :: new ( ) ;
@@ -820,6 +920,7 @@ pub mod experimental {
820
920
events. iter_events( ) ,
821
921
[ 'f' ] [ 'e' , 'z' , 'y' ] [ 'x' , 'w' , 'd' ] [ 'c' , 's' , 'r' ] [ 'b' , 'a' , 'o' ] [ 'n' , 'm' , 'l' ]
822
922
) ;
923
+ assert_eq ! ( events. len( ) , 16 ) ;
823
924
}
824
925
825
926
// Insert in a chunk that does not exist.
@@ -853,6 +954,8 @@ pub mod experimental {
853
954
) ;
854
955
}
855
956
957
+ assert_eq ! ( events. len( ) , 16 ) ;
958
+
856
959
Ok ( ( ) )
857
960
}
858
961
@@ -905,6 +1008,8 @@ pub mod experimental {
905
1008
) ;
906
1009
}
907
1010
1011
+ assert_eq ! ( events. len( ) , 6 ) ;
1012
+
908
1013
Ok ( ( ) )
909
1014
}
910
1015
}
0 commit comments