From a7e36e761519cf8d47865fcbcbde857ac23b1b46 Mon Sep 17 00:00:00 2001 From: Benjamin Bouvier Date: Tue, 17 Dec 2024 17:22:57 +0100 Subject: [PATCH] fix(linked chunk): in LinkedChunk::ritems_from, skip as long as we're on the right chunk The previous code would skip based on the position's index, but not the position's chunk. It could be that the position's chunk is different from the first items chunk, as shown in the example, where the linked chunk ends with a gap; in this case, the position's index would be 0, while the first chunk found while iterating backwards had 3 items. As a result, items 'd' and 'e' would be skipped incorrectly. The fix is to take into account the chunk id when skipping over items. --- .../matrix-sdk-common/src/linked_chunk/mod.rs | 25 +++++++++++++++++-- 1 file changed, 23 insertions(+), 2 deletions(-) diff --git a/crates/matrix-sdk-common/src/linked_chunk/mod.rs b/crates/matrix-sdk-common/src/linked_chunk/mod.rs index 6a67383b014..f42409d68f7 100644 --- a/crates/matrix-sdk-common/src/linked_chunk/mod.rs +++ b/crates/matrix-sdk-common/src/linked_chunk/mod.rs @@ -816,8 +816,9 @@ impl LinkedChunk { .skip_while({ let expected_index = position.index(); - move |(Position(_chunk_identifier, item_index), _item)| { - *item_index != expected_index + move |(Position(chunk_identifier, item_index), _item)| { + *chunk_identifier == position.chunk_identifier() + && *item_index != expected_index } })) } @@ -1813,6 +1814,26 @@ mod tests { assert_matches!(iterator.next(), None); } + #[test] + fn test_ritems_with_final_gap() -> Result<(), Error> { + let mut linked_chunk = LinkedChunk::<3, char, ()>::new(); + linked_chunk.push_items_back(['a', 'b']); + linked_chunk.push_gap_back(()); + linked_chunk.push_items_back(['c', 'd', 'e']); + linked_chunk.push_gap_back(()); + + let mut iterator = linked_chunk.ritems(); + + assert_matches!(iterator.next(), Some((Position(ChunkIdentifier(2), 2), 'e'))); + assert_matches!(iterator.next(), Some((Position(ChunkIdentifier(2), 1), 'd'))); + assert_matches!(iterator.next(), Some((Position(ChunkIdentifier(2), 0), 'c'))); + assert_matches!(iterator.next(), Some((Position(ChunkIdentifier(0), 1), 'b'))); + assert_matches!(iterator.next(), Some((Position(ChunkIdentifier(0), 0), 'a'))); + assert_matches!(iterator.next(), None); + + Ok(()) + } + #[test] fn test_ritems_empty() { let linked_chunk = LinkedChunk::<2, char, ()>::new();