Skip to content

Commit 1ed23db

Browse files
committed
!fourth
1 parent 5e32a97 commit 1ed23db

File tree

1 file changed

+113
-8
lines changed
  • crates/matrix-sdk/src/event_cache

1 file changed

+113
-8
lines changed

crates/matrix-sdk/src/event_cache/store.rs

Lines changed: 113 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -124,6 +124,7 @@ pub mod experimental {
124124
self.chunks.insert_items_at(events.into_iter(), position)
125125
}
126126

127+
/// Insert a gap at a specified position.
127128
pub fn insert_gap_at(&mut self, position: ItemPosition) -> Result<(), LinkedChunkError> {
128129
self.chunks.insert_gap_at(position)
129130
}
@@ -151,6 +152,14 @@ pub mod experimental {
151152
self.chunks.iter_chunks()
152153
}
153154

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+
154163
/// Iterate over the events.
155164
///
156165
/// The most recent event comes first.
@@ -332,9 +341,19 @@ pub mod experimental {
332341
Ok(())
333342
}
334343

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+
335356
/// Get the nth chunk as a mutable reference, if it exists.
336-
///
337-
/// 0 represents the last chunk.
338357
fn nth_chunk_mut<'a>(&'a mut self, nth: ChunkPosition) -> Option<&'a mut Chunk<T, C>> {
339358
let mut chunk =
340359
self.last.or(Some(self.first)).as_mut().map(|chunk| unsafe { chunk.as_mut() });
@@ -368,7 +387,22 @@ pub mod experimental {
368387
///
369388
/// It iterates from the last to the first chunk.
370389
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+
))
372406
}
373407

374408
/// Iterate over the items.
@@ -389,9 +423,14 @@ pub mod experimental {
389423
}
390424

391425
/// The position of a chunk in a [`LinkedChunk`].
426+
///
427+
/// 0 represents the latest chunk.
392428
type ChunkPosition = usize;
393429

394430
/// 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.
395434
#[derive(Debug, PartialEq)]
396435
pub struct ItemPosition(ChunkPosition, usize);
397436

@@ -410,13 +449,13 @@ pub mod experimental {
410449
/// An iterator over a [`LinkedChunk`].
411450
pub struct LinkedChunkIter<'a, T, const CHUNK_CAPACITY: usize> {
412451
chunk: Option<&'a Chunk<T, CHUNK_CAPACITY>>,
413-
position: usize,
452+
position: ChunkPosition,
414453
}
415454

416455
impl<'a, T, const C: usize> LinkedChunkIter<'a, T, C> {
417456
/// 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 }
420459
}
421460
}
422461

@@ -439,7 +478,7 @@ pub mod experimental {
439478

440479
/// This enum represents the content of a [`Chunk`].
441480
#[derive(Debug)]
442-
enum ChunkContent<T> {
481+
pub enum ChunkContent<T> {
443482
/// The chunk represents a gap in the linked chunk, i.e. a hole. It
444483
/// means that some items are missing in this location.
445484
Gap,
@@ -672,7 +711,7 @@ pub mod experimental {
672711
mod tests {
673712
use assert_matches::assert_matches;
674713

675-
use super::{Events, ItemPosition, LinkedChunkError};
714+
use super::{Chunk, ChunkContent, Events, ItemPosition, LinkedChunkError};
676715

677716
macro_rules! assert_events_eq {
678717
( @_ [ $iterator:ident, $chunk_index:ident, $event_index:ident ] { [-] $( $rest:tt )* } { $( $accumulator:tt )* } ) => {
@@ -778,6 +817,67 @@ pub mod experimental {
778817
assert_eq!(events.event_position(|event| *event == 'e'), Some(ItemPosition(3, 1)));
779818
}
780819

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+
781881
#[test]
782882
fn test_insert_items_at() -> Result<(), LinkedChunkError> {
783883
let mut events = Events::<char, 3>::new();
@@ -820,6 +920,7 @@ pub mod experimental {
820920
events.iter_events(),
821921
['f'] ['e', 'z', 'y'] ['x', 'w', 'd'] ['c', 's', 'r'] ['b', 'a', 'o'] ['n', 'm', 'l']
822922
);
923+
assert_eq!(events.len(), 16);
823924
}
824925

825926
// Insert in a chunk that does not exist.
@@ -853,6 +954,8 @@ pub mod experimental {
853954
);
854955
}
855956

957+
assert_eq!(events.len(), 16);
958+
856959
Ok(())
857960
}
858961

@@ -905,6 +1008,8 @@ pub mod experimental {
9051008
);
9061009
}
9071010

1011+
assert_eq!(events.len(), 6);
1012+
9081013
Ok(())
9091014
}
9101015
}

0 commit comments

Comments
 (0)